From fdfd3dcbfbe729aae6a45bdae4b10d12e927d087 Mon Sep 17 00:00:00 2001 From: tanshu Date: Sun, 14 Jun 2020 18:43:10 +0530 Subject: [PATCH] Added: Alembic for migrations Moving from Pyramid to FastAPI --- .gitignore | 2 +- alembic.ini | 85 +++ alembic/README | 1 + alembic/env.py | 70 +++ alembic/script.py.mako | 24 + .../versions/8c06ac60d125_initial_commit.py | 570 ++++++++++++++++++ barker/.env | 18 + barker/__init__.py | 36 -- barker/__main__.py | 3 + barker/core/__init__.py | 0 barker/core/config.py | 44 ++ barker/core/security.py | 131 ++++ barker/core/session.py | 40 ++ barker/db/__init__.py | 0 barker/db/base.py | 31 + barker/db/base_class.py | 16 + barker/db/init_db.py | 154 +++++ barker/db/session.py | 10 + barker/exceptions.py | 6 - barker/main.py | 130 ++++ barker/models/__init__.py | 21 +- barker/models/auth.py | 130 ++-- barker/models/guidtype.py | 57 -- barker/models/master.py | 161 ++--- barker/models/meta.py | 4 +- barker/models/tzinfoutc.py | 9 +- barker/models/validation_exception.py | 11 - barker/models/voucher.py | 132 ++-- barker/renderers.py | 57 -- barker/routers/__init__.py | 0 barker/routers/auth/__init__.py | 0 barker/routers/auth/client.py | 108 ++++ barker/routers/auth/role.py | 144 +++++ barker/routers/auth/user.py | 187 ++++++ barker/routers/customer.py | 86 +++ barker/{views => routers}/device.py | 52 +- barker/{views => routers}/food_table.py | 95 +-- barker/{views => routers}/guest_book.py | 36 +- barker/routers/login.py | 87 +++ barker/routers/menu_category.py | 188 ++++++ barker/{views => routers}/modifier.py | 58 +- barker/routers/modifier_category.py | 219 +++++++ barker/{views => routers}/printer.py | 56 +- barker/routers/product.py | 241 ++++++++ barker/{views => routers}/reports/__init__.py | 0 .../reports/beer_consumption_report.py | 6 +- .../reports/bill_settlement_report.py | 17 +- .../reports/cashier_report.py | 29 +- .../reports/discount_report.py | 13 +- .../reports/product_sale_report.py | 18 +- .../{views => routers}/reports/sale_report.py | 17 +- barker/{views => routers}/reprint.py | 6 +- barker/{views => routers}/role.py | 55 +- barker/routers/sale_category.py | 119 ++++ barker/{views => routers}/section.py | 52 +- barker/{views => routers}/section_printer.py | 41 +- barker/routers/setting.py | 12 + barker/routers/tax.py | 128 ++++ barker/{views => routers}/voucher/__init__.py | 21 +- barker/{views => routers}/voucher/change.py | 0 .../{views => routers}/voucher/merge_move.py | 22 +- .../voucher/receive_payment.py | 7 +- barker/{views => routers}/voucher/save.py | 14 +- barker/{views => routers}/voucher/show.py | 46 +- barker/{views => routers}/voucher/split.py | 23 +- barker/{views => routers}/voucher/update.py | 16 +- barker/{views => routers}/voucher/void.py | 4 +- barker/routes.py | 270 ++------- barker/schemas/__init__.py | 3 + barker/schemas/auth.py | 105 ++++ barker/schemas/master.py | 215 +++++++ barker/scripts/fixtures.py | 236 +------- barker/scripts/initializedb.py | 5 +- barker/security/__init__.py | 39 -- .../permission_authorization_policy.py | 27 - barker/subscribers.py | 2 +- barker/transactional_view_deriver.py | 38 -- barker/views/__init__.py | 64 -- barker/views/customer.py | 74 --- barker/views/login.py | 80 --- barker/views/menu_category.py | 216 ------- barker/views/modifier_category.py | 280 --------- barker/views/product.py | 295 --------- barker/views/sale_category.py | 143 ----- barker/views/setting.py | 10 - barker/views/tax.py | 141 ----- barker/views/user.py | 140 ----- bookie/angular.json | 5 + bookie/package.json | 46 +- bookie/proxy.conf.json | 24 +- bookie/src/app/app.module.ts | 2 +- bookie/src/app/auth/auth-guard.service.ts | 45 +- bookie/src/app/auth/auth.service.ts | 131 ++-- bookie/src/app/auth/login/login.component.ts | 44 +- .../src/app/auth/logout/logout.component.ts | 18 +- .../cashier-report/cashier-report.module.ts | 2 +- bookie/src/app/core/core.module.ts | 20 +- bookie/src/app/core/http-auth-interceptor.ts | 81 +-- bookie/src/app/core/jwt.interceptor.ts | 35 ++ bookie/src/app/core/user.ts | 6 +- bookie/src/app/home/home.component.html | 44 +- .../menu-category-detail.component.ts | 2 +- .../menu-category-list.component.ts | 2 +- .../menu-category/menu-category.service.ts | 21 +- .../modifier-category-detail.component.ts | 2 +- .../modifier-category.service.ts | 27 +- .../modifier-list/modifier-list.component.ts | 2 +- bookie/src/app/nav-bar/nav-bar.component.html | 4 +- bookie/src/app/nav-bar/nav-bar.component.ts | 22 +- .../product-list/product-list-datasource.ts | 6 +- .../product-list/product-list.component.ts | 17 +- bookie/src/app/product/product.service.ts | 29 +- bookie/src/app/roles/role.service.ts | 29 +- .../sale-category-detail.component.ts | 2 +- .../sale-category-list.component.ts | 2 +- .../sale-category/sale-category.service.ts | 31 +- .../sales/bill-type/bill-type.component.ts | 2 +- bookie/src/app/sales/bill.service.ts | 6 +- bookie/src/app/sales/bills/bills.component.ts | 4 +- .../app/sales/discount/discount.component.ts | 2 +- .../app/sales/home/sales-home.component.ts | 21 +- .../sales/modifiers/modifiers.component.ts | 2 +- bookie/src/app/sales/pax/pax.component.ts | 2 +- .../app/sales/quantity/quantity.component.ts | 2 +- .../src/app/sales/reason/reason.component.ts | 2 +- .../receive-payment.component.ts | 2 +- bookie/src/app/sales/sales.module.ts | 13 +- .../tables-dialog/tables-dialog.component.ts | 2 +- bookie/src/app/shared/shared.module.ts | 4 - .../table-detail/table-detail.component.ts | 2 +- .../tables/table-list/table-list.component.ts | 2 +- bookie/src/app/taxes/tax.service.ts | 21 +- .../users/user-list/user-list.component.html | 2 +- bookie/src/app/users/user.service.ts | 24 +- bookie/src/environments/environment.prod.ts | 3 +- bookie/src/environments/environment.ts | 3 +- bookie/src/main.ts | 2 +- bookie/src/tsconfig.app.json | 9 +- requirements.txt | 22 +- 139 files changed, 4017 insertions(+), 3397 deletions(-) create mode 100644 alembic.ini create mode 100644 alembic/README create mode 100644 alembic/env.py create mode 100644 alembic/script.py.mako create mode 100644 alembic/versions/8c06ac60d125_initial_commit.py create mode 100644 barker/.env create mode 100644 barker/__main__.py create mode 100644 barker/core/__init__.py create mode 100644 barker/core/config.py create mode 100644 barker/core/security.py create mode 100644 barker/core/session.py create mode 100644 barker/db/__init__.py create mode 100644 barker/db/base.py create mode 100644 barker/db/base_class.py create mode 100644 barker/db/init_db.py create mode 100644 barker/db/session.py delete mode 100644 barker/exceptions.py create mode 100644 barker/main.py delete mode 100644 barker/models/guidtype.py delete mode 100644 barker/models/validation_exception.py delete mode 100644 barker/renderers.py create mode 100644 barker/routers/__init__.py create mode 100644 barker/routers/auth/__init__.py create mode 100644 barker/routers/auth/client.py create mode 100644 barker/routers/auth/role.py create mode 100644 barker/routers/auth/user.py create mode 100644 barker/routers/customer.py rename barker/{views => routers}/device.py (60%) rename barker/{views => routers}/food_table.py (67%) rename barker/{views => routers}/guest_book.py (73%) create mode 100644 barker/routers/login.py create mode 100644 barker/routers/menu_category.py rename barker/{views => routers}/modifier.py (68%) create mode 100644 barker/routers/modifier_category.py rename barker/{views => routers}/printer.py (61%) create mode 100644 barker/routers/product.py rename barker/{views => routers}/reports/__init__.py (100%) rename barker/{views => routers}/reports/beer_consumption_report.py (91%) rename barker/{views => routers}/reports/bill_settlement_report.py (83%) rename barker/{views => routers}/reports/cashier_report.py (78%) rename barker/{views => routers}/reports/discount_report.py (80%) rename barker/{views => routers}/reports/product_sale_report.py (81%) rename barker/{views => routers}/reports/sale_report.py (90%) rename barker/{views => routers}/reprint.py (61%) rename barker/{views => routers}/role.py (63%) create mode 100644 barker/routers/sale_category.py rename barker/{views => routers}/section.py (53%) rename barker/{views => routers}/section_printer.py (79%) create mode 100644 barker/routers/setting.py create mode 100644 barker/routers/tax.py rename barker/{views => routers}/voucher/__init__.py (87%) rename barker/{views => routers}/voucher/change.py (100%) rename barker/{views => routers}/voucher/merge_move.py (90%) rename barker/{views => routers}/voucher/receive_payment.py (89%) rename barker/{views => routers}/voucher/save.py (86%) rename barker/{views => routers}/voucher/show.py (79%) rename barker/{views => routers}/voucher/split.py (88%) rename barker/{views => routers}/voucher/update.py (87%) rename barker/{views => routers}/voucher/void.py (93%) create mode 100644 barker/schemas/__init__.py create mode 100644 barker/schemas/auth.py create mode 100644 barker/schemas/master.py delete mode 100644 barker/security/__init__.py delete mode 100644 barker/security/permission_authorization_policy.py delete mode 100644 barker/transactional_view_deriver.py delete mode 100644 barker/views/__init__.py delete mode 100644 barker/views/customer.py delete mode 100644 barker/views/login.py delete mode 100644 barker/views/menu_category.py delete mode 100644 barker/views/modifier_category.py delete mode 100644 barker/views/product.py delete mode 100644 barker/views/sale_category.py delete mode 100644 barker/views/setting.py delete mode 100644 barker/views/tax.py delete mode 100644 barker/views/user.py create mode 100644 bookie/src/app/core/jwt.interceptor.ts diff --git a/.gitignore b/.gitignore index fddd889..1770ee1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ *.pyc -env +venv .project .pydevproject */__pycache__/ diff --git a/alembic.ini b/alembic.ini new file mode 100644 index 0000000..bfcc3c7 --- /dev/null +++ b/alembic.ini @@ -0,0 +1,85 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# timezone to use when rendering the date +# within the migration file as well as the filename. +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; this defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path +# version_locations = %(here)s/bar %(here)s/bat alembic/versions + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks=black +# black.type=console_scripts +# black.entrypoint=black +# black.options=-l 79 + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/alembic/README b/alembic/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/alembic/env.py b/alembic/env.py new file mode 100644 index 0000000..3301eac --- /dev/null +++ b/alembic/env.py @@ -0,0 +1,70 @@ +import logging + +from sqlalchemy import create_engine +from sqlalchemy import pool + +from alembic import context +from barker.core.config import settings + +logging.basicConfig() +logging.getLogger("sqlalchemy.engine").setLevel(settings.ALEMBIC_LOG_LEVEL) +logging.getLogger("alembic").setLevel(settings.ALEMBIC_LOG_LEVEL) + +# Interpret the config file for Python logging. +# This line sets up loggers basically. + +from barker.models.auth import User # noqa + +target_metadata = User.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = settings.SQLALCHEMY_DATABASE_URI + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + compare_type=True, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = create_engine(settings.SQLALCHEMY_DATABASE_URI, poolclass=pool.NullPool,) + + with connectable.connect() as connection: + context.configure(connection=connection, target_metadata=target_metadata, compare_type=True) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/script.py.mako b/alembic/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/alembic/versions/8c06ac60d125_initial_commit.py b/alembic/versions/8c06ac60d125_initial_commit.py new file mode 100644 index 0000000..68e2208 --- /dev/null +++ b/alembic/versions/8c06ac60d125_initial_commit.py @@ -0,0 +1,570 @@ +"""Initial Commit + +Revision ID: 8c06ac60d125 +Revises: +Create Date: 2020-06-04 08:14:34.132248 + +""" +import uuid + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from barker.models import Section, ModifierCategory, SettleOption, Customer, DbSetting +from barker.models.auth import User, Permission # noqa + +# revision identifiers, used by Alembic. +revision = "8c06ac60d125" +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "clients", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("enabled", sa.Boolean(), nullable=False), + sa.Column("otp", sa.Integer(), nullable=True), + sa.Column("creation_date", sa.DateTime(timezone=True), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_clients")), + sa.UniqueConstraint("name", name=op.f("uq_clients_name")), + ) + op.create_table( + "customers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("company", sa.Unicode(length=255), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("phone", sa.Unicode(length=255), nullable=True), + sa.Column("address", sa.Unicode(length=255), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_customers")), + sa.UniqueConstraint("phone", name=op.f("uq_customers_phone")), + ) + op.create_table( + "menu_categories", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("discount_limit", sa.Numeric(), nullable=False), + sa.Column("is_active", sa.Boolean(), nullable=False), + sa.Column("is_fixture", sa.Boolean(), nullable=False), + sa.Column("sort_order", sa.Numeric(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_menu_categories")), + sa.UniqueConstraint("name", name=op.f("uq_menu_categories_name")), + ) + op.create_table( + "modifier_categories", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("minimum", sa.Integer(), nullable=False), + sa.Column("maximum", sa.Integer(), nullable=True), + sa.Column("is_active", sa.Boolean(), nullable=False), + sa.Column("sort_order", sa.Numeric(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_modifier_categories")), + sa.UniqueConstraint("name", name=op.f("uq_modifier_categories_name")), + ) + op.create_table( + "permissions", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_permissions")), + sa.UniqueConstraint("name", name=op.f("uq_permissions_name")), + ) + op.create_table( + "printers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("address", sa.Unicode(length=255), nullable=False), + sa.Column("cut_code", sa.Unicode(length=255), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_printers")), + sa.UniqueConstraint("address", name=op.f("uq_printers_address")), + sa.UniqueConstraint("name", name=op.f("uq_printers_name")), + ) + op.create_table( + "roles", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_roles")), + sa.UniqueConstraint("name", name=op.f("uq_roles_name")), + ) + op.create_table( + "sections", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_sections")), + sa.UniqueConstraint("name", name=op.f("uq_sections_name")), + ) + op.create_table( + "settings", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("data", sa.JSON(), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_settings")), + sa.UniqueConstraint("name", name=op.f("uq_settings_name")), + ) + op.create_table( + "settle_options", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("show_in_choices", sa.Boolean(), nullable=False), + sa.Column("display_group", sa.Integer(), nullable=False), + sa.Column("is_print", sa.Boolean(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_settle_options")), + sa.UniqueConstraint("name", name=op.f("uq_settle_options_name")), + ) + op.create_table( + "taxes", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("rate", sa.Numeric(), nullable=False), + sa.Column("is_fixture", sa.Boolean(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_taxes")), + sa.UniqueConstraint("name", name=op.f("uq_taxes_name")), + ) + op.create_table( + "users", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("password", sa.Unicode(length=60), nullable=False), + sa.Column("locked_out", sa.Boolean(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_users")), + sa.UniqueConstraint("name", name=op.f("uq_users_name")), + ) + op.create_table( + "devices", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("section_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["section_id"], ["sections.id"], name=op.f("fk_devices_section_id_sections")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_devices")), + sa.UniqueConstraint("name", name=op.f("uq_devices_name")), + ) + op.create_table( + "food_tables", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("seats", sa.Numeric(), nullable=False), + sa.Column("section_id", postgresql.UUID(), nullable=False), + sa.Column("is_active", sa.Boolean(), nullable=False), + sa.Column("sort_order", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint(["section_id"], ["sections.id"], name=op.f("fk_food_tables_section_id_sections")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_food_tables")), + sa.UniqueConstraint("name", name=op.f("uq_food_tables_name")), + ) + op.create_table( + "guest_book", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("customer_id", postgresql.UUID(), nullable=False), + sa.Column("pax", sa.Numeric(), nullable=False), + sa.Column("creation_date", sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(["customer_id"], ["customers.id"], name=op.f("fk_guest_book_customer_id_customers")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_guest_book")), + ) + op.create_table( + "modifiers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("show_in_bill", sa.Boolean(), nullable=False), + sa.Column("price", sa.Numeric(), nullable=False), + sa.Column("is_active", sa.Boolean(), nullable=False), + sa.Column("modifier_category_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint( + ["modifier_category_id"], + ["modifier_categories.id"], + name=op.f("fk_modifiers_modifier_category_id_modifier_categories"), + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_modifiers")), + sa.UniqueConstraint("name", name=op.f("uq_modifiers_name")), + ) + op.create_table( + "role_permissions", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("permission_id", postgresql.UUID(), nullable=False), + sa.Column("role_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint( + ["permission_id"], ["permissions.id"], name=op.f("fk_role_permissions_permission_id_permissions") + ), + sa.ForeignKeyConstraint(["role_id"], ["roles.id"], name=op.f("fk_role_permissions_role_id_roles")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_role_permissions")), + sa.UniqueConstraint("permission_id", "role_id", name=op.f("uq_role_permissions_permission_id")), + ) + op.create_table( + "sale_categories", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("tax_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["tax_id"], ["taxes.id"], name=op.f("fk_sale_categories_tax_id_taxes")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_sale_categories")), + sa.UniqueConstraint("name", name=op.f("uq_sale_categories_name")), + ) + op.create_table( + "section_printers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("menu_category_id", postgresql.UUID(), nullable=True), + sa.Column("section_id", postgresql.UUID(), nullable=False), + sa.Column("printer_id", postgresql.UUID(), nullable=False), + sa.Column("copies", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint( + ["menu_category_id"], + ["menu_categories.id"], + name=op.f("fk_section_printers_menu_category_id_menu_categories"), + ), + sa.ForeignKeyConstraint(["printer_id"], ["printers.id"], name=op.f("fk_section_printers_printer_id_printers")), + sa.ForeignKeyConstraint(["section_id"], ["sections.id"], name=op.f("fk_section_printers_section_id_sections")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_section_printers")), + sa.UniqueConstraint("menu_category_id", "section_id", name=op.f("uq_section_printers_menu_category_id")), + ) + op.create_table( + "user_roles", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("user_id", postgresql.UUID(), nullable=False), + sa.Column("role_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["role_id"], ["roles.id"], name=op.f("fk_user_roles_role_id_roles")), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_user_roles_user_id_users")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_user_roles")), + sa.UniqueConstraint("user_id", "role_id", name=op.f("uq_user_roles_user_id")), + ) + op.create_table( + "products", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("name", sa.Unicode(length=255), nullable=False), + sa.Column("units", sa.Unicode(length=255), nullable=False), + sa.Column("menu_category_id", postgresql.UUID(), nullable=False), + sa.Column("sale_category_id", postgresql.UUID(), nullable=False), + sa.Column("price", sa.Numeric(), nullable=False), + sa.Column("has_happy_hour", sa.Boolean(), nullable=False), + sa.Column("is_not_available", sa.Boolean(), nullable=False), + sa.Column("quantity", sa.Numeric(), nullable=False), + sa.Column("is_active", sa.Boolean(), nullable=False), + sa.Column("sort_order", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint( + ["menu_category_id"], ["menu_categories.id"], name=op.f("fk_products_menu_category_id_menu_categories") + ), + sa.ForeignKeyConstraint( + ["sale_category_id"], ["sale_categories.id"], name=op.f("fk_products_sale_category_id_sale_categories") + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_products")), + sa.UniqueConstraint("name", "units", name=op.f("uq_products_name")), + ) + op.create_table( + "vouchers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("date", sa.DateTime(), nullable=False), + sa.Column("pax", sa.Numeric(), nullable=False), + sa.Column("bill_id", sa.Numeric(), nullable=True), + sa.Column("kot_id", sa.Numeric(), nullable=False), + sa.Column("creation_date", sa.DateTime(timezone=True), nullable=False), + sa.Column("last_edit_date", sa.DateTime(timezone=True), nullable=False), + sa.Column("food_table_id", postgresql.UUID(), nullable=False), + sa.Column("customer_id", postgresql.UUID(), nullable=True), + sa.Column("narration", sa.Unicode(length=1000), nullable=False), + sa.Column("reason", sa.Unicode(length=255), nullable=True), + sa.Column("voucher_type", sa.Integer(), nullable=False), + sa.Column("user_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["customer_id"], ["customers.id"], name=op.f("fk_vouchers_customer_id_customers")), + sa.ForeignKeyConstraint( + ["food_table_id"], ["food_tables.id"], name=op.f("fk_vouchers_food_table_id_food_tables") + ), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_vouchers_user_id_users")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_vouchers")), + sa.UniqueConstraint("bill_id", "voucher_type", name=op.f("uq_vouchers_bill_id")), + sa.UniqueConstraint("kot_id", name=op.f("uq_vouchers_kot_id")), + ) + op.create_index(op.f("ix_vouchers_date"), "vouchers", ["date"], unique=False) + op.create_table( + "kots", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("voucher_id", postgresql.UUID(), nullable=False), + sa.Column("code", sa.Numeric(), nullable=False), + sa.Column("food_table_id", postgresql.UUID(), nullable=False), + sa.Column("date", sa.DateTime(), nullable=False), + sa.Column("user_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["food_table_id"], ["food_tables.id"], name=op.f("fk_kots_food_table_id_food_tables")), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_kots_user_id_users")), + sa.ForeignKeyConstraint(["voucher_id"], ["vouchers.id"], name=op.f("fk_kots_voucher_id_vouchers")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_kots")), + sa.UniqueConstraint("code", name=op.f("uq_kots_code")), + ) + op.create_index(op.f("ix_kots_date"), "kots", ["date"], unique=False) + op.create_index(op.f("ix_kots_voucher_id"), "kots", ["voucher_id"], unique=False) + op.create_table( + "modifier_categories_products", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("product_id", postgresql.UUID(), nullable=False), + sa.Column("modifier_categories_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint( + ["modifier_categories_id"], + ["modifier_categories.id"], + name=op.f("fk_modifier_categories_products_modifier_categories_id_modifier_categories"), + ), + sa.ForeignKeyConstraint( + ["product_id"], ["products.id"], name=op.f("fk_modifier_categories_products_product_id_products") + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_modifier_categories_products")), + sa.UniqueConstraint( + "product_id", "modifier_categories_id", name=op.f("uq_modifier_categories_products_product_id") + ), + ) + op.create_table( + "overview", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("voucher_id", postgresql.UUID(), nullable=False), + sa.Column("food_table_id", postgresql.UUID(), nullable=False), + sa.Column("guest_book_id", postgresql.UUID(), nullable=True), + sa.Column("status", sa.Unicode(length=255), nullable=False), + sa.ForeignKeyConstraint( + ["food_table_id"], ["food_tables.id"], name=op.f("fk_overview_food_table_id_food_tables") + ), + sa.ForeignKeyConstraint( + ["guest_book_id"], ["guest_book.id"], name=op.f("fk_overview_guest_book_id_guest_book") + ), + sa.ForeignKeyConstraint(["voucher_id"], ["vouchers.id"], name=op.f("fk_overview_voucher_id_vouchers")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_overview")), + sa.UniqueConstraint("food_table_id", name=op.f("uq_overview_food_table_id")), + sa.UniqueConstraint("guest_book_id", name=op.f("uq_overview_guest_book_id")), + sa.UniqueConstraint("voucher_id", name=op.f("uq_overview_voucher_id")), + ) + op.create_table( + "reprints", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("date", sa.DateTime(), nullable=False), + sa.Column("voucher_id", postgresql.UUID(), nullable=False), + sa.Column("user_id", postgresql.UUID(), nullable=False), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], name=op.f("fk_reprints_user_id_users")), + sa.ForeignKeyConstraint(["voucher_id"], ["vouchers.id"], name=op.f("fk_reprints_voucher_id_vouchers")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_reprints")), + ) + op.create_index(op.f("ix_reprints_date"), "reprints", ["date"], unique=False) + op.create_index(op.f("ix_reprints_voucher_id"), "reprints", ["voucher_id"], unique=False) + op.create_table( + "settlements", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("voucher_id", postgresql.UUID(), nullable=False), + sa.Column("settled", sa.Integer(), nullable=False), + sa.Column("amount", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint(["settled"], ["settle_options.id"], name=op.f("fk_settlements_settled_settle_options")), + sa.ForeignKeyConstraint(["voucher_id"], ["vouchers.id"], name=op.f("fk_settlements_voucher_id_vouchers")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_settlements")), + sa.UniqueConstraint("voucher_id", "settled", name=op.f("uq_settlements_voucher_id")), + ) + op.create_index(op.f("ix_settlements_voucher_id"), "settlements", ["voucher_id"], unique=False) + op.create_table( + "inventories", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("kot_id", postgresql.UUID(), nullable=False), + sa.Column("product_id", postgresql.UUID(), nullable=False), + sa.Column("quantity", sa.Numeric(), nullable=True), + sa.Column("price", sa.Numeric(), nullable=True), + sa.Column("is_happy_hour", sa.Boolean(), nullable=False), + sa.Column("tax_rate", sa.Numeric(), nullable=True), + sa.Column("tax_id", postgresql.UUID(), nullable=False), + sa.Column("discount", sa.Numeric(), nullable=True), + sa.Column("sort_order", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint(["kot_id"], ["kots.id"], name=op.f("fk_inventories_kot_id_kots")), + sa.ForeignKeyConstraint(["product_id"], ["products.id"], name=op.f("fk_inventories_product_id_products")), + sa.ForeignKeyConstraint(["tax_id"], ["taxes.id"], name=op.f("fk_inventories_tax_id_taxes")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_inventories")), + sa.UniqueConstraint("kot_id", "product_id", "is_happy_hour", "price", name=op.f("uq_inventories_kot_id")), + ) + op.create_index(op.f("ix_inventories_kot_id"), "inventories", ["kot_id"], unique=False) + op.create_table( + "inventory_modifiers", + sa.Column("id", postgresql.UUID(), nullable=False), + sa.Column("inventory_id", postgresql.UUID(), nullable=False), + sa.Column("modifier_id", postgresql.UUID(), nullable=False), + sa.Column("price", sa.Numeric(), nullable=False), + sa.ForeignKeyConstraint( + ["inventory_id"], ["inventories.id"], name=op.f("fk_inventory_modifiers_inventory_id_inventories") + ), + sa.ForeignKeyConstraint( + ["modifier_id"], ["modifiers.id"], name=op.f("fk_inventory_modifiers_modifier_id_modifiers") + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_inventory_modifiers")), + sa.UniqueConstraint("inventory_id", "modifier_id", name=op.f("uq_inventory_modifiers_inventory_id")), + ) + + op.execute(Permission.__table__.insert().values(id="7669dfc9-cc75-4e48-b267-145c8832a83c", name="Guest Book")) + op.execute(Permission.__table__.insert().values(id="5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c", name="Printers")) + op.execute(Permission.__table__.insert().values(id="c973f32c-a37b-496a-8dc5-60d2e4c39e97", name="Sections")) + op.execute(Permission.__table__.insert().values(id="7a04ba63-5d08-4078-9051-a6d91cce3e48", name="Section Printers")) + op.execute(Section.__table__.insert().values(id="3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df", name="Main")) + + op.execute( + ModifierCategory.__table__.insert().values( + id="e046ad33-dc65-4c78-8833-c3d3538d44c0", + name="Old Modifiers", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + op.execute( + ModifierCategory.__table__.insert().values( + id="b572f401-3c2f-48b9-8973-ada5a6e4d3a6", + name="Bar Instructions", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + op.execute( + ModifierCategory.__table__.insert().values( + id="caa72832-5034-405e-8442-68a8cc12ace9", + name="Delivery", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + op.execute( + ModifierCategory.__table__.insert().values( + id="d6a0595f-e209-42e4-bb12-b7499f9a9c4d", + name="Kitchen Instructions", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + op.execute( + ModifierCategory.__table__.insert().values( + id="60ca9122-adc5-463b-ad5f-33a68df8c3ae", + name="Mixers", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + op.execute( + ModifierCategory.__table__.insert().values( + id="ef5b1a0b-5eb1-45ff-bd82-3209c8b888df", + name="Pasta Sauce", + maximum=None, + minimum=0, + is_active=True, + sort_order=0, + ) + ) + + op.execute( + SettleOption.__table__.insert().values( + id=1, name="Unsettled", show_in_choices=False, display_group=1, is_print=True + ) + ) + op.execute( + SettleOption.__table__.insert().values(id=2, name="Cash", show_in_choices=True, display_group=2, is_print=False) + ) + op.execute( + SettleOption.__table__.insert().values( + id=3, name="Credit Card", show_in_choices=True, display_group=2, is_print=True + ) + ) + op.execute( + SettleOption.__table__.insert().values( + id=4, name="No Charge", show_in_choices=True, display_group=3, is_print=True + ) + ) + op.execute( + SettleOption.__table__.insert().values( + id=5, name="Bill To Company", show_in_choices=True, display_group=2, is_print=True + ) + ) + op.execute( + SettleOption.__table__.insert().values(id=6, name="Tip", show_in_choices=True, display_group=2, is_print=True) + ) + op.execute( + SettleOption.__table__.insert().values( + id=7, name="Round Off", show_in_choices=False, display_group=1, is_print=False + ) + ) + op.execute( + SettleOption.__table__.insert().values( + id=8, name="Amount", show_in_choices=False, display_group=1, is_print=False + ) + ) + op.execute( + SettleOption.__table__.insert().values(id=9, name="Void", show_in_choices=True, display_group=1, is_print=True) + ) + op.execute( + SettleOption.__table__.insert().values( + id=10, name="Staff", show_in_choices=True, display_group=4, is_print=True + ) + ) + op.execute( + Customer.__table__.insert().values( + id="2c716f4b-0736-429a-ad51-610d7c47cb5e", company="", name="Cash", phone="", address="" + ) + ) + op.execute( + DbSetting.__table__.insert().values( + id="fb738ba2-a3c9-40ed-891c-b930e6454974", + name="Header", + data={ + "Text": """ Hops n Grains + The Microbrewery + SCO 358, Sector 9, Panchkula + A Unit of Peitho Foods Pvt. Ltd. + CIN: U15139CH2010PTC032202 + (Reg Add: Plot No. 907, Indl Area II, Chd) + TIN: 06592507323 + Service Tax: AAFCP5097GSD001 + """ + }, + ) + ) + op.execute( + DbSetting.__table__.insert().values( + id="f7799871-d16e-4c4d-9b57-2299a5839acb", + name="Footer", + data={"Text": "Call: 0172-4026666, 8054923853, 8054923856"}, + ) + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("inventory_modifiers") + op.drop_index(op.f("ix_inventories_kot_id"), table_name="inventories") + op.drop_table("inventories") + op.drop_index(op.f("ix_settlements_voucher_id"), table_name="settlements") + op.drop_table("settlements") + op.drop_index(op.f("ix_reprints_voucher_id"), table_name="reprints") + op.drop_index(op.f("ix_reprints_date"), table_name="reprints") + op.drop_table("reprints") + op.drop_table("overview") + op.drop_table("modifier_categories_products") + op.drop_index(op.f("ix_kots_voucher_id"), table_name="kots") + op.drop_index(op.f("ix_kots_date"), table_name="kots") + op.drop_table("kots") + op.drop_index(op.f("ix_vouchers_date"), table_name="vouchers") + op.drop_table("vouchers") + op.drop_table("products") + op.drop_table("user_roles") + op.drop_table("section_printers") + op.drop_table("sale_categories") + op.drop_table("role_permissions") + op.drop_table("modifiers") + op.drop_table("guest_book") + op.drop_table("food_tables") + op.drop_table("devices") + op.drop_table("users") + op.drop_table("taxes") + op.drop_table("settle_options") + op.drop_table("settings") + op.drop_table("sections") + op.drop_table("roles") + op.drop_table("printers") + op.drop_table("permissions") + op.drop_table("modifier_categories") + op.drop_table("menu_categories") + op.drop_table("customers") + op.drop_table("clients") + # ### end Alembic commands ### diff --git a/barker/.env b/barker/.env new file mode 100644 index 0000000..ebe500e --- /dev/null +++ b/barker/.env @@ -0,0 +1,18 @@ +HOST=0.0.0.0 +PORT=6543 +LOG_LEVEL=WARN +DEBUG=true +SQLALCHEMY_DATABASE_URI= +MODULE_NAME=barker.main +PROJECT_NAME=barker +POSTGRES_SERVER= +POSTGRES_USER= +POSTGRES_PASSWORD= +POSTGRES_DB= + +SECRET_KEY= +ALGORITHM=HS256 +JWT_TOKEN_EXPIRE_MINUTES=30 + +ALEMBIC_LOG_LEVEL=INFO +ALEMBIC_SQLALCHEMY_LOG_LEVEL=WARN diff --git a/barker/__init__.py b/barker/__init__.py index ca20cb0..e69de29 100644 --- a/barker/__init__.py +++ b/barker/__init__.py @@ -1,36 +0,0 @@ -import os - -from pyramid.config import Configurator -from pyramid.session import SignedCookieSessionFactory -from barker.renderers import json_renderer, CSVRenderer -from barker.transactional_view_deriver import transactional_view - - -def main(global_config, **settings): - """ This function returns a Pyramid WSGI application. - """ - if 'sqlalchemy.url' not in settings: - DB_NAME = os.environ['DB_NAME'] - DB_USER = os.environ['DB_USER'] - DB_PASS = os.environ['DB_PASS'] - DB_URI = 'postgresql://{0}:{1}@postgres:5432/{2}'.format( - DB_USER, DB_PASS, DB_NAME - ) - settings['sqlalchemy.url'] = DB_URI - - SECRET_KEY = os.environ.get('SECRET_KEY', settings.get('secret_key', '')) - session_factory = SignedCookieSessionFactory(SECRET_KEY, timeout=None) - - config = Configurator( - settings=settings, - session_factory=session_factory - ) - config.include('.security') - config.include('.models') - config.include('.routes') - config.add_view_deriver(transactional_view) - config.add_renderer(name='json', factory=json_renderer) - config.add_renderer(name='csv', factory=CSVRenderer) - config.scan() - - return config.make_wsgi_app() diff --git a/barker/__main__.py b/barker/__main__.py new file mode 100644 index 0000000..c470f10 --- /dev/null +++ b/barker/__main__.py @@ -0,0 +1,3 @@ +from barker.main import init + +init() diff --git a/barker/core/__init__.py b/barker/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/barker/core/config.py b/barker/core/config.py new file mode 100644 index 0000000..e7caa39 --- /dev/null +++ b/barker/core/config.py @@ -0,0 +1,44 @@ +from dotenv import load_dotenv +import secrets +from typing import Any, Dict, Optional + +from pydantic import BaseSettings, PostgresDsn, validator + + +class Settings(BaseSettings): + # openssl rand -hex 32 + SECRET_KEY: str = secrets.token_urlsafe(32) + ALGORITHM: str = "HS256" + JWT_TOKEN_EXPIRE_MINUTES: int = 30 + HOST: str = "0.0.0.0" + PORT: int = 80 + DEBUG: bool = False + LOG_LEVEL: str = "NOTSET" + POSTGRES_SERVER: str = "" + POSTGRES_USER: str = "postgres" + POSTGRES_PASSWORD: str = "" + POSTGRES_DB: str = "" + SQLALCHEMY_DATABASE_URI: Optional[str] = None + + @validator("SQLALCHEMY_DATABASE_URI", pre=True) + def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any: + if isinstance(v, str): + return v + return PostgresDsn.build( + scheme="postgresql", + user=values.get("POSTGRES_USER"), + password=values.get("POSTGRES_PASSWORD"), + host=values.get("POSTGRES_SERVER"), + path=f"/{values.get('POSTGRES_DB') or ''}", + ) + + ALEMBIC_LOG_LEVEL: str = "INFO" + ALEMBIC_SQLALCHEMY_LOG_LEVEL: str = "WARN" + + class Config: + case_sensitive = True + env_file = ".env" + + +load_dotenv() +settings = Settings() diff --git a/barker/core/security.py b/barker/core/security.py new file mode 100644 index 0000000..b71ee71 --- /dev/null +++ b/barker/core/security.py @@ -0,0 +1,131 @@ +import uuid +from datetime import datetime, timedelta +from typing import List, Optional +from jwt import PyJWTError + +from fastapi import Depends, HTTPException, status, Security +from fastapi.security import OAuth2PasswordBearer, SecurityScopes +from pydantic import BaseModel, ValidationError +from sqlalchemy.orm import Session +from jose import jwt +from jose.exceptions import ExpiredSignatureError + +from barker.core.config import settings +from barker.models.auth import User as UserModel, Client +from ..db.session import SessionLocal + + +# to get a string like this run: +from ..schemas.auth import UserToken + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token", scopes={}) + + +class Token(BaseModel): + access_token: str + token_type: str + + +class TokenData(BaseModel): + username: str = None + scopes: List[str] = [] + + +def f7(seq): + seen = set() + seen_add = seen.add + return [x for x in seq if not (x in seen or seen_add(x))] + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +def create_access_token(*, data: dict, expires_delta: timedelta = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + return encoded_jwt + + +def get_user(username: str, id_: str, locked_out: bool, scopes: List[str]) -> UserToken: + return UserToken(id_=uuid.UUID(id_), name=username, locked_out=locked_out, password="", permissions=scopes,) + + +def authenticate_user( + username: str, password: str, client_id: Optional[int], otp: int, db: Session +) -> Optional[UserModel]: + user = UserModel.auth(username, password, db) + return user + + +def client_allowed(user: UserModel, client_id: int, otp: Optional[int] = None, db: Session = None) -> (bool, int): + client = db.query(Client).filter(Client.id == client_id).first() if client_id else None + allowed = "clients" in set([p.name.replace(" ", "-").lower() for r in user.roles for p in r.permissions]) + if allowed or True: + return True, 0 + elif client is None: + client = Client.create(db) + return False, client.id + elif client.enabled: + return True, client.id + elif client.otp == otp: + client.otp = None + client.enabled = True + return True, client.id + else: + return False, client.id + + +async def get_current_user(security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme),) -> UserToken: + if security_scopes.scopes: + authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' + else: + authenticate_value = f"Bearer" + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": authenticate_value}, + ) + try: + payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) + username: str = payload.get("sub") + if username is None: + raise credentials_exception + token_scopes = payload.get("scopes", []) + token_data = TokenData(scopes=token_scopes, username=username) + except (PyJWTError, ValidationError, ExpiredSignatureError): + raise credentials_exception + user = get_user( + username=token_data.username, + id_=payload.get("userId", None), + locked_out=payload.get("lockedOut", True), + scopes=token_scopes, + ) + if user is None: + raise credentials_exception + for scope in security_scopes.scopes: + if scope not in token_data.scopes: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not enough permissions", + headers={"WWW-Authenticate": authenticate_value}, + ) + return user + + +async def get_current_active_user( + current_user: UserToken = Security(get_current_user, scopes=["authenticated"]) +) -> UserToken: + if current_user.locked_out: + raise HTTPException(status_code=400, detail="Inactive user") + return current_user diff --git a/barker/core/session.py b/barker/core/session.py new file mode 100644 index 0000000..13abcd8 --- /dev/null +++ b/barker/core/session.py @@ -0,0 +1,40 @@ +from datetime import date, timedelta + + +def get_date(session) -> str: + if "date" not in session: + session["date"] = date.today().strftime("%d-%b-%Y") + return session["date"] + + +def set_date(date_, session): + session["date"] = date_ + return session["date"] + + +def get_start_date(session): + if "start" not in session: + session["start"] = get_first_day(date.today()).strftime("%d-%b-%Y") + return session["start"] + + +def get_finish_date(session): + if "finish" not in session: + session["finish"] = get_last_day(date.today()).strftime("%d-%b-%Y") + return session["finish"] + + +def set_period(start, finish, session): + session["start"] = start if isinstance(start, str) else start.strftime("%d-%b-%Y") + session["finish"] = finish if isinstance(finish, str) else finish.strftime("%d-%b-%Y") + + +def get_first_day(dt, d_years=0, d_months=0): + # d_years, d_months are "deltas" to apply to dt + y, m = dt.year + d_years, dt.month + d_months + a, m = divmod(m - 1, 12) + return date(y + a, m + 1, 1) + + +def get_last_day(dt): + return get_first_day(dt, 0, 1) + timedelta(-1) diff --git a/barker/db/__init__.py b/barker/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/barker/db/base.py b/barker/db/base.py new file mode 100644 index 0000000..c82573a --- /dev/null +++ b/barker/db/base.py @@ -0,0 +1,31 @@ +# Import all the models, so that Base has them before being +# imported by Alembic +from barker.db.base_class import Base # noqa +from brewman.models import ( + Client, + user_group, + role_group, + User, + LoginHistory, + Role, + Permission, + Product, + AttendanceType, + CostCentre, + Employee, + Account, + AccountBase, + AccountType, + ProductGroup, + Recipe, + RecipeItem, + Attendance, + Batch, + Fingerprint, + Inventory, + Journal, + Product, + EmployeeBenefit, + Voucher, + VoucherType, +) # noqa diff --git a/barker/db/base_class.py b/barker/db/base_class.py new file mode 100644 index 0000000..98c6156 --- /dev/null +++ b/barker/db/base_class.py @@ -0,0 +1,16 @@ +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.schema import MetaData + +# Recommended naming convention used by Alembic, as various different database +# providers will autogenerate vastly different names making migrations more +# difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html +NAMING_CONVENTION = { + "ix": "ix_%(column_0_label)s", + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s", +} + +metadata = MetaData(naming_convention=NAMING_CONVENTION) +Base = declarative_base(metadata=metadata) diff --git a/barker/db/init_db.py b/barker/db/init_db.py new file mode 100644 index 0000000..ac65e92 --- /dev/null +++ b/barker/db/init_db.py @@ -0,0 +1,154 @@ +import uuid + +from sqlalchemy.orm import Session + +from barker.core.config import settings +from brewman.db import base # noqa: F401 +from barker.models import Permission, Section, ModifierCategory, SettleOption, Customer, DbSetting, Role, User + +# make sure all SQL Alchemy models are imported (app.db.base) before initializing DB +# otherwise, SQL Alchemy might fail to initialize relationships properly +# for more details: https://github.com/tiangolo/full-stack-fastapi-postgresql/issues/28 + + +def init_db(db: Session) -> None: + # Tables should be created with Alembic migrations + # But if you don't want to use migrations, create + # the tables un-commenting the next line + # Base.metadata.create_all(bind=engine) + + prod = True + if prod: + db.add(Permission("Guest Book", uuid.UUID("7669dfc9-cc75-4e48-b267-145c8832a83c"))) + db.add(Permission("Printers", uuid.UUID("5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c"))) + db.add(Permission("Sections", uuid.UUID("c973f32c-a37b-496a-8dc5-60d2e4c39e97"))) + db.add(Permission("Section Printers", uuid.UUID("7a04ba63-5d08-4078-9051-a6d91cce3e48"), )) + else: + add_permissions(db) + + main_section = Section("Main", uuid.UUID("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df")) + db.add(main_section) + mcs = [ + ModifierCategory("Old Modifiers", 0, 0, True, 0, uuid.UUID("e046ad33-dc65-4c78-8833-c3d3538d44c0"), ), + ModifierCategory("Bar Instructions", 0, 0, True, 0, uuid.UUID("b572f401-3c2f-48b9-8973-ada5a6e4d3a6"), ), + ModifierCategory("Delivery", 0, 0, True, 0, uuid.UUID("caa72832-5034-405e-8442-68a8cc12ace9"), ), + ModifierCategory("Kitchen Instructions", 0, 0, True, 0, uuid.UUID("d6a0595f-e209-42e4-bb12-b7499f9a9c4d"), ), + ModifierCategory("Mixers", 0, 0, True, 0, uuid.UUID("60ca9122-adc5-463b-ad5f-33a68df8c3ae"), ), + ModifierCategory("Pasta Sauce", 0, 0, True, 0, uuid.UUID("ef5b1a0b-5eb1-45ff-bd82-3209c8b888df"), ), + ] + for item in mcs: + db.add(item) + + options = [ + SettleOption("Unsettled", False, 1, True, 1), + SettleOption("Cash", True, 2, False, 2), + SettleOption("Credit Card", True, 2, True, 3), + SettleOption("No Charge", True, 3, True, 4), + SettleOption("Bill To Company", True, 2, True, 5), + SettleOption("Tip", True, 2, True, 6), + SettleOption("Round Off", False, 1, False, 7), + SettleOption("Amount", False, 1, False, 8), + SettleOption("Void", True, 1, True, 9), + SettleOption("Staff", True, 4, True, 10), + ] + for option in options: + db.add(option) + db.add(Customer("", "Cash", "", "", uuid.UUID("2c716f4b-0736-429a-ad51-610d7c47cb5e"))) + db.add( + DbSetting( + uuid.UUID("fb738ba2-a3c9-40ed-891c-b930e6454974"), + "Header", + { + "Text": """ Hops n Grains + The Microbrewery + SCO 358, Sector 9, Panchkula + A Unit of Peitho Foods Pvt. Ltd. + CIN: U15139CH2010PTC032202 + (Reg Add: Plot No. 907, Indl Area II, Chd) + TIN: 06592507323 + Service Tax: AAFCP5097GSD001 + """ + }, + ) + ) + db.add( + DbSetting( + uuid.UUID("f7799871-d16e-4c4d-9b57-2299a5839acb"), + "Footer", + {"Text": "Call: 0172-4026666, 8054923853, 8054923856"}, + ) + ) + + +def add_permissions(db: Session): + permissions = [ + Permission("Accounts Audit", uuid.UUID("f30fd1fb-df09-46f5-8c5d-181fd46f38de")), + Permission("Beer Consumption", uuid.UUID("efbb8f31-9631-4491-92f4-17cc98e6a0c0")), + Permission("Bill Details", uuid.UUID("612bb529-b50d-4653-a1c0-ebb725c7d728")), + Permission("Cashier Checkout", uuid.UUID("a86f8bcf-66f4-4c44-89e1-b714488b8331")), + Permission("Change Rate", uuid.UUID("10c63aae-0e48-4e54-b3b8-dd8a80b88fbf")), + Permission("Customers", uuid.UUID("e5fef133-cdbe-441f-bb54-1f0db0c5db79")), + Permission("Discount", uuid.UUID("1f66f131-0105-4466-8f8e-21e0ccc2ac27")), + Permission("Discount Report", uuid.UUID("0d8ba1d5-6731-417c-ab0e-be03cfdc96db")), + Permission("Edit Printed Bill", uuid.UUID("4ff6cb0f-93cb-4760-8219-4de280eaa957")), + Permission("Edit Printed Product", uuid.UUID("959713be-d753-4e14-8ecd-e27f33587499"),), + Permission("Guest Book", uuid.UUID("7669dfc9-cc75-4e48-b267-145c8832a83c")), + Permission("Machines", uuid.UUID("f12b573f-edcb-490d-91c3-fa76f6502ffd")), + Permission("Merge Kots", uuid.UUID("bed774e9-4857-43b0-a4af-40230c9eb5db")), + Permission("Merge Tables", uuid.UUID("dfc493fb-ac14-4602-8596-f93f47b617de")), + Permission("Modifiers", uuid.UUID("9dc82529-1e86-41b4-a152-eaea9f775fea")), + Permission("Move Kot to New Table", uuid.UUID("5ed5796a-ca99-437f-8f67-483b1ade81ed"),), + Permission("Move Table", uuid.UUID("cfdb69c9-d37a-40af-bef2-e29c04602543")), + Permission("NC Product", uuid.UUID("54263587-773e-4cbb-b1e4-4e814141158e")), + Permission("Open Bill", uuid.UUID("5811d233-a1ae-4d32-af52-cebbf46d274a")), + Permission("Owner", uuid.UUID("6d109b66-8452-42aa-bbe9-d4cef440b7a1")), + Permission("Print Bill", uuid.UUID("92242eae-bd38-4223-829b-2f981933b7f2")), + Permission("Print Kot", uuid.UUID("0eef56fb-7741-49fd-8b84-5069cccae767")), + Permission("Products", uuid.UUID("f1f892ed-34aa-4c50-be12-dbaf48be7d4c")), + Permission("Roles", uuid.UUID("d39f86f6-14e4-4fc3-b07e-01e2501a6f65")), + Permission("Sales", uuid.UUID("92ba45c4-2d34-4cbd-b5b8-d9164c3595d5")), + Permission("Sales Analysis", uuid.UUID("0c1acb7c-9116-46e2-a3be-9d632e811330")), + Permission("Sales Detail", uuid.UUID("e6476396-ef83-4c47-bc20-9f3b936813f9")), + Permission("Settle Bill", uuid.UUID("9f7b658a-25bc-4a53-8560-2dde1c7a188a")), + Permission("Split Bill", uuid.UUID("0a8cfaf4-624e-478f-be65-c3b6392078c7")), + Permission("Tables", uuid.UUID("ac4512e8-efdd-429e-a7ae-a34d18782663")), + Permission("Tax Analysis", uuid.UUID("bab36396-53dd-44ea-ab3c-426efa7830c8")), + Permission("Taxes", uuid.UUID("5c8fcdde-460d-4047-810f-e34fb899fadc")), + Permission("Users", uuid.UUID("243447b8-b403-47e6-8b3d-8e76f4df44a9")), + Permission("Void Bill", uuid.UUID("e3c76262-adc0-4936-8b4d-217c6292298b")), + Permission("Void or Reprinted Bill Report", uuid.UUID("30c8e743-c710-42d7-843a-0b75543b3516"),), + Permission("Printers", uuid.UUID("5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c")), + Permission("Sections", uuid.UUID("c973f32c-a37b-496a-8dc5-60d2e4c39e97")), + ] + + for permission in permissions: + db.add(permission) + + roles = [ + Role("Owner", uuid.UUID("06ec0ddb-949c-4357-aefb-65e5e55a9ae7")), + Role("Accountant", uuid.UUID("57d4538c-257a-4bf4-9a42-342992cb6af3")), + Role("Bar Captain", uuid.UUID("5a8ebb05-4817-45a5-866f-e523c30bfa25")), + Role("Captain", uuid.UUID("8db7001f-0964-4607-84f5-b6f4d9183fef")), + Role("Cashier", uuid.UUID("f1f0b112-1404-4b55-b121-f07ee6e08d12")), + Role("Controller", uuid.UUID("d9a5a478-1fe4-4847-84da-63cfba1a094a")), + Role("Manager", uuid.UUID("90ea7b14-9057-4bfd-a7cf-0ee7a3bb2463")), + Role("Senior Captain", uuid.UUID("d9b1b433-1ed5-4109-8ab2-cbd48ff010cd")), + Role("Server", uuid.UUID("6b378b71-f091-4485-a589-8db94ff1d6a4")), + ] + + roles[0].permissions = permissions + roles[1].permissions = list(permissions[i] for i in [2, 3, 11, 18, 24, 25, 26, 30, 34]) + roles[2].permissions = list(permissions[i] for i in [26]) + roles[3].permissions = list(permissions[i] for i in [16]) + roles[4].permissions = list(permissions[i] for i in [20, 24, 27]) + roles[5].permissions = list(permissions[i] for i in [0, 2, 7, 11, 18, 22, 24, 25, 26, 34]) + roles[6].permissions = list(permissions[i] for i in [2, 3, 4, 5, 6, 8, 11, 14, 18, 22, 25, 26, 28, 29, 33, 34]) + roles[7].permissions = list(permissions[i] for i in [9, 12, 13, 15, 16]) + roles[8].permissions = list(permissions[i] for i in [21, 24]) + + for role in roles: + db.add(role) + + admin = User("Admin", "123456", False) + admin.roles.append(roles[0]) + db.add(admin) diff --git a/barker/db/session.py b/barker/db/session.py new file mode 100644 index 0000000..b296b8b --- /dev/null +++ b/barker/db/session.py @@ -0,0 +1,10 @@ +import logging +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from barker.core.config import settings + +logging.basicConfig() +logging.getLogger("sqlalchemy.engine").setLevel(settings.LOG_LEVEL) +engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/barker/exceptions.py b/barker/exceptions.py deleted file mode 100644 index 33063f2..0000000 --- a/barker/exceptions.py +++ /dev/null @@ -1,6 +0,0 @@ -class ValidationFailure(Exception): - def __init__(self, message): - self.message = message - - def __str__(self): - return self.message diff --git a/barker/main.py b/barker/main.py new file mode 100644 index 0000000..71f1f4a --- /dev/null +++ b/barker/main.py @@ -0,0 +1,130 @@ +import uvicorn +from fastapi import FastAPI +from starlette.middleware.sessions import SessionMiddleware + +from .routers import ( +# account, +# account_types, +# attendance_report, +# attendance_types, +# attendance, +# batch, +# cost_centre, +# credit_salary, +# db_image, +# db_integrity, +# employee, +# employee_attendance, +# employee_benefit, +# fingerprint, +# incentive, +# issue, +# issue_grid, +# lock_information, +# maintenance, + menu_category, + modifier_category, + product, +# rebase, +# reset_stock, +# recipe, + login, + sale_category, + tax, +# journal, +# purchase, +# purchase_return, +# voucher, +) +from .routers.auth import client, user, role +# from .routers.reports import ( +# ledger, +# balance_sheet, +# profit_loss, +# closing_stock, +# cash_flow, +# daybook, +# net_transactions, +# product_ledger, +# purchase_entries, +# purchases, +# raw_material_cost, +# reconcile, +# stock_movement, +# trial_balance, +# unposted, +# ) + +from .db.base_class import Base +from .core.config import settings +from .db.session import engine + +Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +app.add_middleware(SessionMiddleware, secret_key="29e4c76b6c") +# app.include_router(db_image.router, prefix="/db-image", tags=["db-image"]) +app.include_router(login.router, tags=["login"]) +# app.include_router(account.router, prefix="/api/accounts", tags=["accounts"]) +# app.include_router(account_types.router, prefix="/api/account-types", tags=["accounts"]) +# app.include_router(attendance.router, prefix="/api/attendance", tags=["attendance"]) +# app.include_router(attendance_types.router, prefix="/api/attendance-types", tags=["attendance"]) +# app.include_router(employee_attendance.router, prefix="/api/employee-attendance", tags=["attendance"]) +# app.include_router(employee_attendance.router, prefix="/api/employee-attendance", tags=["attendance"]) +# app.include_router(attendance_report.router, prefix="/attendance-report", tags=["attendance"]) + +# app.include_router(cost_centre.router, prefix="/api/cost-centres", tags=["cost-centres"]) +# app.include_router(employee.router, prefix="/api/employees", tags=["employees"]) +# app.include_router(fingerprint.router, prefix="/api/fingerprint", tags=["employees"]) +app.include_router(menu_category.router, prefix="/api/menu-categories", tags=["products"]) +app.include_router(product.router, prefix="/api/products", tags=["products"]) +app.include_router(sale_category.router, prefix="/api/sale-categories", tags=["products"]) +app.include_router(tax.router, prefix="/api/taxes", tags=["products"]) + +app.include_router(modifier_category.router, prefix="/api/modifier-categories", tags=["modifiers"]) + +app.include_router(client.router, prefix="/api/clients", tags=["clients"]) +app.include_router(role.router, prefix="/api/roles", tags=["users"]) +app.include_router(user.router, prefix="/api/users", tags=["users"]) + +# app.include_router(ledger.router, prefix="/api/ledger", tags=["reports"]) +# app.include_router(balance_sheet.router, prefix="/api/balance-sheet", tags=["reports"]) +# app.include_router(profit_loss.router, prefix="/api/profit-loss", tags=["reports"]) +# app.include_router(closing_stock.router, prefix="/api/closing-stock", tags=["reports"]) +# app.include_router(cash_flow.router, prefix="/api/cash-flow", tags=["reports"]) +# app.include_router(daybook.router, prefix="/api/daybook", tags=["reports"]) +# app.include_router(net_transactions.router, prefix="/api/net-transactions", tags=["reports"]) +# app.include_router(product_ledger.router, prefix="/api/product-ledger", tags=["reports"]) +# app.include_router(purchase_entries.router, prefix="/api/purchase-entries", tags=["reports"]) +# app.include_router(purchases.router, prefix="/api/purchases", tags=["reports"]) +# app.include_router(raw_material_cost.router, prefix="/api/raw-material-cost", tags=["reports"]) +# app.include_router(reconcile.router, prefix="/api/reconcile", tags=["reports"]) +# app.include_router(stock_movement.router, prefix="/api/stock-movement", tags=["reports"]) +# app.include_router(trial_balance.router, prefix="/api/trial-balance", tags=["reports"]) +# app.include_router(unposted.router, prefix="/api/unposted", tags=["reports"]) + +# app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"]) +# app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"]) +# app.include_router(journal.router, prefix="/api/journal", tags=["vouchers"]) +# app.include_router(journal.router, prefix="/api/payment", tags=["vouchers"]) +# app.include_router(journal.router, prefix="/api/receipt", tags=["vouchers"]) +# app.include_router(purchase.router, prefix="/api/purchase", tags=["vouchers"]) +# app.include_router(purchase_return.router, prefix="/api/purchase-return", tags=["vouchers"]) +# app.include_router(issue.router, prefix="/api/issue", tags=["vouchers"]) +# app.include_router(employee_benefit.router, prefix="/api/employee-benefit", tags=["vouchers"]) +# app.include_router(incentive.router, prefix="/api/incentive", tags=["vouchers"]) +# app.include_router(credit_salary.router, prefix="/api/credit-salary", tags=["vouchers"]) +# app.include_router(voucher.router, prefix="/api", tags=["vouchers"]) + +# app.include_router(lock_information.router, prefix="/api/lock-information", tags=["settings"]) +# app.include_router(maintenance.router, prefix="/api/maintenance", tags=["settings"]) + +# app.include_router(db_integrity.router, prefix="/api/db-integrity", tags=["management"]) +# app.include_router(reset_stock.router, prefix="/api/reset-stock", tags=["management"]) +# app.include_router(rebase.router, prefix="/api/rebase", tags=["management"]) + + +def init(): + uvicorn.run(app, host=settings.HOST, port=settings.PORT) diff --git a/barker/models/__init__.py b/barker/models/__init__.py index a29d1f5..0b17868 100644 --- a/barker/models/__init__.py +++ b/barker/models/__init__.py @@ -14,7 +14,7 @@ from .voucher import ( Reprint, Settlement, Voucher, - VoucherType + VoucherType, ) from .master import ( Customer, @@ -30,23 +30,23 @@ from .master import ( SectionPrinter, SaleCategory, SettleOption, - Tax + Tax, ) from .auth import ( Client, - LoginHistory, Permission, Role, role_permissions, User, - user_roles + user_roles, ) + # run configure_mappers after defining all of the models to ensure # all relationships can be setup configure_mappers() -def get_engine(settings, prefix='sqlalchemy.'): +def get_engine(settings, prefix="sqlalchemy."): return engine_from_config(settings, prefix) @@ -78,8 +78,7 @@ def get_tm_session(session_factory, transaction_manager): """ dbsession = session_factory() - zope.sqlalchemy.register( - dbsession, transaction_manager=transaction_manager) + zope.sqlalchemy.register(dbsession, transaction_manager=transaction_manager) return dbsession @@ -93,15 +92,15 @@ def includeme(config): settings = config.get_settings() # use pyramid_tm to hook the transaction lifecycle to the request - config.include('pyramid_tm') + config.include("pyramid_tm") session_factory = get_session_factory(get_engine(settings)) - config.registry['dbsession_factory'] = session_factory + config.registry["dbsession_factory"] = session_factory # make request.dbsession available for use in Pyramid config.add_request_method( # r.tm is the transaction manager used by pyramid_tm lambda r: get_tm_session(session_factory, r.tm), - 'dbsession', - reify=True + "dbsession", + reify=True, ) diff --git a/barker/models/auth.py b/barker/models/auth.py index 6f262f1..924dcd6 100644 --- a/barker/models/auth.py +++ b/barker/models/auth.py @@ -6,81 +6,78 @@ from datetime import datetime from sqlalchemy.schema import ForeignKey, Table from sqlalchemy import Column, Boolean, Unicode, Integer, DateTime, UniqueConstraint -from sqlalchemy.orm import synonym, relationship +from sqlalchemy.orm import synonym, relationship, Session -from barker.models.guidtype import GUID +from sqlalchemy.dialects.postgresql import UUID from .meta import Base def encrypt(val): - return md5(val.encode('utf-8') + "v2".encode('utf-8')).hexdigest() + return md5(val.encode("utf-8") + "v2".encode("utf-8")).hexdigest() class Client(Base): - __tablename__ = 'clients' + __tablename__ = "clients" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - code = Column('code', Integer, unique=True, nullable=False) - name = Column('name', Unicode(255), unique=True, nullable=False) - enabled = Column('enabled', Boolean, nullable=False) - otp = Column('otp', Integer) - creation_date = Column('creation_date', DateTime(timezone=True), nullable=False) + id = Column("id", Integer, primary_key=True) + name = Column("name", Unicode(255), unique=True, nullable=False) + enabled = Column("enabled", Boolean, nullable=False) + otp = Column("otp", Integer) + creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) - login_history = relationship('LoginHistory', backref='client') - - def __init__(self, code=None, name=None, enabled=False, otp=None, creation_date=None, id=None): - self.code = code + def __init__(self, id_=None, name=None, enabled=False, otp=None, creation_date=None): + self.id = id_ self.name = name self.enabled = enabled self.otp = otp - self.creation_date = datetime.utcnow() if creation_date is None else creation_date - self.id = id + self.creation_date = creation_date or datetime.utcnow() @classmethod - def by_code(cls, code, dbsession): - if code is None: + def by_id(cls, id_: int, db: Session): + if id_ is None: return None - if not isinstance(code, int): - code = int(code) - return dbsession.query(cls).filter(cls.code == code).first() + if not isinstance(id_, int): + id_ = int(id_) + return db.query(cls).filter(cls.id == id_).first() @classmethod - def create(cls, dbsession): + def create(cls, db: Session): client_code = random.randint(1000, 9999) otp = random.randint(1000, 9999) - name = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) + name = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) client = Client(client_code, name, False, otp) - dbsession.add(client) + db.add(client) return client user_roles = Table( - 'user_roles', Base.metadata, - Column('id', GUID(), primary_key=True, default=uuid.uuid4), - Column('user_id', GUID(), ForeignKey('users.id'), nullable=False), - Column('role_id', GUID(), ForeignKey('roles.id'), nullable=False), - UniqueConstraint('user_id', 'role_id') + "user_roles", + Base.metadata, + Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4), + Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False), + Column("role_id", UUID(as_uuid=True), ForeignKey("roles.id"), nullable=False), + UniqueConstraint("user_id", "role_id"), ) role_permissions = Table( - 'role_permissions', Base.metadata, - Column('id', GUID(), primary_key=True, default=uuid.uuid4), - Column('permission_id', GUID(), ForeignKey('permissions.id'), nullable=False), - Column('role_id', GUID(), ForeignKey('roles.id'), nullable=False), - UniqueConstraint('permission_id', 'role_id') + "role_permissions", + Base.metadata, + Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4), + Column("permission_id", UUID(as_uuid=True), ForeignKey("permissions.id"), nullable=False), + Column("role_id", UUID(as_uuid=True), ForeignKey("roles.id"), nullable=False), + UniqueConstraint("permission_id", "role_id"), ) class User(Base): - __tablename__ = 'users' + __tablename__ = "users" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('name', Unicode(255), unique=True, nullable=False) - _password = Column('password', Unicode(60), nullable=False) - locked_out = Column('locked_out', Boolean, nullable=False) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + name = Column("name", Unicode(255), unique=True, nullable=False) + _password = Column("password", Unicode(60), nullable=False) + locked_out = Column("locked_out", Boolean, nullable=False) roles = relationship("Role", secondary=user_roles, order_by="Role.name") - login_history = relationship('LoginHistory', backref='user') def _get_password(self): return self._password @@ -89,65 +86,50 @@ class User(Base): self._password = encrypt(password) password = property(_get_password, _set_password) - password = synonym('_password', descriptor=password) + password = synonym("_password", descriptor=password) @property def __name__(self): return self.name - def __init__(self, name=None, password=None, locked_out=None, id=None): + def __init__(self, name=None, password=None, locked_out=None, id_=None): self.name = name self.password = password self.locked_out = locked_out - self.id = id + self.id = id_ @classmethod - def auth(cls, name, password, dbsession): + def auth(cls, name, password, db: Session): if password is None: - return False, None - user = dbsession.query(User).filter(User.name.ilike(name)).first() + return None + user = db.query(User).filter(User.name.ilike(name)).first() if not user: - return False, None + return None if user.password != encrypt(password) or user.locked_out: - return False, None + return None else: - return True, user - - -class LoginHistory(Base): - __tablename__ = 'login_history' - __table_args__ = (UniqueConstraint('user_id', 'client_id', 'date'),) - id = Column('login_history_id', GUID(), primary_key=True, default=uuid.uuid4) - user_id = Column('user_id', GUID(), ForeignKey('users.id'), nullable=False) - client_id = Column('client_id', GUID(), ForeignKey('clients.id'), nullable=False) - date = Column('date', DateTime(timezone=True), nullable=False) - - def __init__(self, user_id=None, client_id=None, date=None, id=None): - self.user_id = user_id - self.client_id = client_id - self.date = datetime.utcnow() if date is None else date - self.id = id + return user class Role(Base): - __tablename__ = 'roles' + __tablename__ = "roles" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('name', Unicode(255), unique=True) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + name = Column("name", Unicode(255), unique=True) - def __init__(self, name=None, id=None): + def __init__(self, name=None, id_=None): self.name = name - self.id = id + self.id = id_ class Permission(Base): - __tablename__ = 'permissions' + __tablename__ = "permissions" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('name', Unicode(255), unique=True) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + name = Column("name", Unicode(255), unique=True) roles = relationship("Role", secondary=role_permissions, backref="permissions") - def __init__(self, name=None, id=None): + def __init__(self, name=None, id_=None): self.name = name - self.id = id + self.id = id_ diff --git a/barker/models/guidtype.py b/barker/models/guidtype.py deleted file mode 100644 index 73aebbc..0000000 --- a/barker/models/guidtype.py +++ /dev/null @@ -1,57 +0,0 @@ -import uuid -from sqlalchemy.dialects.postgresql import UUID -from sqlalchemy.dialects.sqlite import BLOB -from sqlalchemy.types import TypeDecorator, CHAR, Binary - - -class GUID(TypeDecorator): - """Platform-independent GUID type. - - Uses Postgresql's UUID type, otherwise uses - CHAR(32), storing as stringified hex values. - - """ - impl = Binary - - # if dialect.value == 'postgresql': - # impl = CHAR - # elif dialect.value == 'mysql': - # impl = MSBinary - # elif dialect.valie == 'sqlite': - # impl = Binary - # else: - # impl = Binary - - def load_dialect_impl(self, dialect): - if dialect.name == 'postgresql': - return dialect.type_descriptor(UUID()) - elif dialect.name == 'sqlite': - return dialect.type_descriptor(BLOB()) - else: - return dialect.type_descriptor(CHAR(32)) - - def process_bind_param(self, value, dialect): - if value is None: - return None - elif dialect.name == 'postgresql': - return str(value) - elif not isinstance(value, uuid.UUID): - raise ValueError('value %s is not a valid uuid.UUID' % value) - else: - return value.bytes - # if not isinstance(value, uuid.UUID): - # return "%.32x" % uuid.UUID(value) - # else: - # # hexstring - # return "%.32x" % value - - def process_result_value(self, value, dialect=None): - if value is None: - return None - elif isinstance(value, bytes): - return uuid.UUID(bytes=value) - else: - return uuid.UUID(value) - - def is_mutable(self): - return False diff --git a/barker/models/master.py b/barker/models/master.py index 2f8776b..3cddd54 100644 --- a/barker/models/master.py +++ b/barker/models/master.py @@ -15,13 +15,12 @@ from sqlalchemy import ( from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship from .meta import Base -from barker.models.guidtype import GUID - +from sqlalchemy.dialects.postgresql import UUID class Customer(Base): __tablename__ = "customers" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) company = Column("company", Unicode(255), nullable=False) name = Column("name", Unicode(255), nullable=False) phone = Column("phone", Unicode(255), nullable=True, unique=True) @@ -31,12 +30,12 @@ class Customer(Base): def __name__(self): return self.name - def __init__(self, company=None, name=None, phone=None, address=None, id=None): + def __init__(self, company=None, name=None, phone=None, address=None, id_=None): self.company = company self.name = name self.phone = phone self.address = address - self.id = id + self.id = id_ @classmethod def cash(cls): @@ -46,109 +45,93 @@ class Customer(Base): class FoodTable(Base): __tablename__ = "food_tables" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) seats = Column("seats", Numeric, nullable=False) - section_id = Column("section_id", GUID(), ForeignKey("sections.id"), nullable=False) - + section_id = Column("section_id", UUID(as_uuid=True), ForeignKey("sections.id"), nullable=False) section = relationship("Section", foreign_keys=section_id) - is_active = Column("is_active", Boolean, nullable=False) - sort_order = Column("sort_order", Numeric, nullable=False) + sort_order = Column("sort_order", Integer, nullable=False) @property def __name__(self): return self.name def __init__( - self, - name=None, - seats=None, - section_id=None, - is_active=None, - sort_order=0, - id=None, + self, name=None, seats=None, section_id=None, is_active=None, sort_order=0, id_=None, ): self.name = name self.seats = seats self.section_id = section_id self.is_active = is_active self.sort_order = sort_order - self.id = id + self.id = id_ class Tax(Base): __tablename__ = "taxes" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) rate = Column("rate", Numeric, nullable=False) is_fixture = Column("is_fixture", Boolean, nullable=False) - def __init__(self, name=None, rate=None, is_fixture=False, id=None): + def __init__(self, name=None, rate=None, is_fixture=False, id_=None): self.name = name self.rate = rate self.is_fixture = is_fixture - self.id = id + self.id = id_ class MenuCategory(Base): __tablename__ = "menu_categories" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) discount_limit = Column("discount_limit", Numeric, nullable=False) is_active = Column("is_active", Boolean, nullable=False) is_fixture = Column("is_fixture", Boolean, nullable=False) - sort_order = Column("sort_order", Numeric, nullable=False) + sort_order = Column("sort_order", Integer, nullable=False) - def __init__( - self, name, discount_limit, is_active, sort_order, is_fixture=False, id=None - ): + def __init__(self, name, discount_limit, is_active, sort_order, is_fixture=False, id_=None): self.name = name self.discount_limit = discount_limit self.is_active = is_active self.sort_order = sort_order self.is_fixture = is_fixture - self.id = id + self.id = id_ class SaleCategory(Base): __tablename__ = "sale_categories" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) - tax_id = Column("tax_id", GUID(), ForeignKey("taxes.id"), nullable=False) - + tax_id = Column("tax_id", UUID(as_uuid=True), ForeignKey("taxes.id"), nullable=False) tax = relationship("Tax", foreign_keys=tax_id) - def __init__(self, name, tax_id=False, id=None): + def __init__(self, name, tax_id=False, id_=None): self.name = name self.tax_id = tax_id - self.id = id + self.id = id_ class Product(Base): __tablename__ = "products" __table_args__ = (UniqueConstraint("name", "units"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False) units = Column("units", Unicode(255), nullable=False) - menu_category_id = Column( - "menu_category_id", GUID(), ForeignKey("menu_categories.id"), nullable=False - ) - sale_category_id = Column( - "sale_category_id", GUID(), ForeignKey("sale_categories.id"), nullable=False - ) + menu_category_id = Column("menu_category_id", UUID(as_uuid=True), ForeignKey("menu_categories.id"), nullable=False) + sale_category_id = Column("sale_category_id", UUID(as_uuid=True), ForeignKey("sale_categories.id"), nullable=False) price = Column("price", Numeric, nullable=False) has_happy_hour = Column("has_happy_hour", Boolean, nullable=False) is_not_available = Column("is_not_available", Boolean, nullable=False) quantity = Column("quantity", Numeric, nullable=False) - is_active = Column("is_active", Boolean, nullable=False) - sort_order = Column("sort_order", Numeric, nullable=False) + sort_order = Column("sort_order", Integer, nullable=False) menu_category = relationship("MenuCategory", backref="products") sale_category = relationship("SaleCategory", backref="products") @@ -171,7 +154,7 @@ class Product(Base): quantity=None, is_active=None, sort_order=0, - id=None, + id_=None, ): self.name = name self.units = units @@ -183,7 +166,7 @@ class Product(Base): self.quantity = quantity self.is_active = is_active self.sort_order = sort_order - self.id = id + self.id = id_ @hybrid_property def full_name(self): @@ -195,10 +178,7 @@ class Product(Base): def can_delete(self, advanced_delete): if self.is_fixture: - return ( - False, - "{0} is a fixture and cannot be edited or deleted.".format(self.name), - ) + return False, f"{self.name} is a fixture and cannot be edited or deleted." if self.is_active: return False, "Product is active" if len(self.inventories) > 0 and not advanced_delete: @@ -209,14 +189,9 @@ class Product(Base): modifier_categories_products = Table( "modifier_categories_products", Base.metadata, - Column("id", GUID(), primary_key=True, default=uuid.uuid4), - Column("product_id", GUID(), ForeignKey("products.id"), nullable=False), - Column( - "modifier_categories_id", - GUID(), - ForeignKey("modifier_categories.id"), - nullable=False, - ), + Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4), + Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False), + Column("modifier_categories_id", UUID(as_uuid=True), ForeignKey("modifier_categories.id"), nullable=False,), UniqueConstraint("product_id", "modifier_categories_id"), ) @@ -224,15 +199,17 @@ modifier_categories_products = Table( class ModifierCategory(Base): __tablename__ = "modifier_categories" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) minimum = Column("minimum", Integer, nullable=False) maximum = Column("maximum", Integer, nullable=True) is_active = Column("is_active", Boolean, nullable=False) - sort_order = Column("sort_order", Numeric, nullable=False) + sort_order = Column("sort_order", Integer, nullable=False) - def __init__(self, name=None, minimum=None, maximum=None, is_active=True, sort_order=0, id=None): - self.id = id + def __init__( + self, name=None, minimum=None, maximum=None, is_active=True, sort_order=0, id_=None, + ): + self.id = id_ self.name = name self.minimum = minimum self.maximum = maximum @@ -243,30 +220,19 @@ class ModifierCategory(Base): class Modifier(Base): __tablename__ = "modifiers" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), nullable=False, unique=True) show_in_bill = Column("show_in_bill", Boolean, nullable=False) price = Column("price", Numeric, nullable=False) is_active = Column("is_active", Boolean, nullable=False) - modifier_category_id = Column( - "modifier_category_id", - GUID(), - ForeignKey("modifier_categories.id"), - nullable=False, - ) + modifier_category_id = Column("modifier_category_id", UUID(as_uuid=True), ForeignKey("modifier_categories.id"), nullable=False,) modifier_category = relationship("ModifierCategory", backref="modifiers") def __init__( - self, - name=None, - show_in_bill=None, - price=None, - modifier_category_id=None, - is_active=True, - id=None, + self, name=None, show_in_bill=None, price=None, modifier_category_id=None, is_active=True, id_=None, ): - self.id = id + self.id = id_ self.name = name self.show_in_bill = show_in_bill self.price = price @@ -277,12 +243,12 @@ class Modifier(Base): class DbSetting(Base): __tablename__ = "settings" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True, nullable=False) data = Column("data", JSON) - def __init__(self, id=None, name=None, data=None): - self.id = id + def __init__(self, id_=None, name=None, data=None): + self.id = id_ self.name = name self.data = data @@ -290,39 +256,39 @@ class DbSetting(Base): class Section(Base): __tablename__ = "sections" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True, nullable=False) - def __init__(self, name=None, id=None): - self.id = id + def __init__(self, name=None, id_=None): + self.id = id_ self.name = name class Device(Base): __tablename__ = "devices" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True, nullable=False) - section_id = Column("section_id", GUID(), ForeignKey("sections.id"), nullable=False) + section_id = Column("section_id", UUID(as_uuid=True), ForeignKey("sections.id"), nullable=False) section = relationship("Section", foreign_keys=section_id) - def __init__(self, name=None, section_id=None, id=None): + def __init__(self, name=None, section_id=None, id_=None): self.name = name self.section_id = section_id - self.id = id + self.id = id_ class Printer(Base): __tablename__ = "printers" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = Column("name", Unicode(255), unique=True, nullable=False) address = Column("address", Unicode(255), unique=True, nullable=False) cut_code = Column("cut_code", Unicode(255), nullable=False) - def __init__(self, name=None, address=None, cut_code=None, id=None): - self.id = id + def __init__(self, name=None, address=None, cut_code=None, id_=None): + self.id = id_ self.name = name self.address = address self.cut_code = cut_code @@ -332,19 +298,18 @@ class SectionPrinter(Base): __tablename__ = "section_printers" __table_args__ = (UniqueConstraint("menu_category_id", "section_id"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - menu_category_id = Column( - "menu_category_id", GUID(), ForeignKey("menu_categories.id") - ) - section_id = Column("section_id", GUID(), ForeignKey("sections.id"), nullable=False) - printer_id = Column("printer_id", GUID(), ForeignKey("printers.id"), nullable=False) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + menu_category_id = Column("menu_category_id", UUID(as_uuid=True), ForeignKey("menu_categories.id")) + section_id = Column("section_id", UUID(as_uuid=True), ForeignKey("sections.id"), nullable=False) + printer_id = Column("printer_id", UUID(as_uuid=True), ForeignKey("printers.id"), nullable=False) copies = Column("copies", Numeric, nullable=False) menu_category = relationship("MenuCategory", backref="section_printers") section = relationship("Section", backref="section_printers") printer = relationship("Printer", backref="section_printers") - def __init__(self, menu_category_id, section_id, printer_id, copies): + def __init__(self, menu_category_id=None, section_id=None, printer_id=None, copies=None, id_=None): + self.id = id_ self.menu_category_id = menu_category_id self.section_id = section_id self.printer_id = printer_id @@ -357,14 +322,14 @@ class SettleOption(Base): id = Column("id", Integer, primary_key=True) name = Column("name", Unicode(255), unique=True, nullable=False) show_in_choices = Column("show_in_choices", Boolean, nullable=False) - group = Column("display_group", Integer, nullable=False) + display_group = Column("display_group", Integer, nullable=False) is_print = Column("is_print", Boolean, nullable=False) - def __init__(self, name, show_in_choices, group, is_print, id): - self.id = id + def __init__(self, name=None, show_in_choices=None, display_group=None, is_print=None, id_=None): + self.id = id_ self.name = name self.show_in_choices = show_in_choices - self.group = group + self.display_group = display_group self.is_print = is_print @classmethod diff --git a/barker/models/meta.py b/barker/models/meta.py index 0682247..98c6156 100644 --- a/barker/models/meta.py +++ b/barker/models/meta.py @@ -5,11 +5,11 @@ from sqlalchemy.schema import MetaData # providers will autogenerate vastly different names making migrations more # difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html NAMING_CONVENTION = { - "ix": 'ix_%(column_0_label)s', + "ix": "ix_%(column_0_label)s", "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", - "pk": "pk_%(table_name)s" + "pk": "pk_%(table_name)s", } metadata = MetaData(naming_convention=NAMING_CONVENTION) diff --git a/barker/models/tzinfoutc.py b/barker/models/tzinfoutc.py index ae86317..7f6927c 100644 --- a/barker/models/tzinfoutc.py +++ b/barker/models/tzinfoutc.py @@ -6,6 +6,7 @@ HOUR = timedelta(hours=1) # A UTC class. + class UTC(tzinfo): """UTC""" @@ -37,9 +38,9 @@ def get_age(old_date, now=None): delta = now - old_date if delta.days > 0: - return '{0} days'.format(delta.days) + return "{0} days".format(delta.days) if delta.seconds > 3600: - return '{0} hours'.format(delta.seconds // 3600) + return "{0} hours".format(delta.seconds // 3600) if delta.seconds > 60: - return '{0} minutes'.format(delta.seconds // 60) - return '{0} seconds'.format(delta.seconds) + return "{0} minutes".format(delta.seconds // 60) + return "{0} seconds".format(delta.seconds) diff --git a/barker/models/validation_exception.py b/barker/models/validation_exception.py deleted file mode 100644 index 2e80b40..0000000 --- a/barker/models/validation_exception.py +++ /dev/null @@ -1,11 +0,0 @@ -class ValidationError(Exception): - def __init__(self, message, errors=None): - self.message = message - # Call the base class constructor with the parameters it needs - Exception.__init__(self, message) - - # Now for your custom code... - self.errors = errors - - def __str__(self): - return self.message diff --git a/barker/models/voucher.py b/barker/models/voucher.py index 704249b..d7be9ba 100644 --- a/barker/models/voucher.py +++ b/barker/models/voucher.py @@ -16,7 +16,7 @@ from sqlalchemy import ( case, ) from sqlalchemy.orm import relationship, backref, synonym -from barker.models.guidtype import GUID +from sqlalchemy.dialects.postgresql import UUID from .meta import Base @@ -30,10 +30,8 @@ class VoucherType(Enum): class GuestBook(Base): __tablename__ = "guest_book" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - customer_id = Column( - "customer_id", GUID(), ForeignKey("customers.id"), nullable=False - ) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + customer_id = Column("customer_id", UUID(as_uuid=True), ForeignKey("customers.id"), nullable=False) pax = Column("pax", Numeric, nullable=False) date = Column("creation_date", DateTime(timezone=True), nullable=False) @@ -48,20 +46,10 @@ class GuestBook(Base): class Overview(Base): __tablename__ = "overview" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column( - "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, unique=True - ) - food_table_id = Column( - "food_table_id", - GUID(), - ForeignKey("food_tables.id"), - nullable=False, - unique=True, - ) - guest_book_id = Column( - "guest_book_id", GUID(), ForeignKey("guest_book.id"), unique=True - ) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + voucher_id = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False, unique=True) + food_table_id = Column("food_table_id", UUID(as_uuid=True), ForeignKey("food_tables.id"), nullable=False, unique=True,) + guest_book_id = Column("guest_book_id", UUID(as_uuid=True), ForeignKey("guest_book.id"), unique=True) status = Column("status", Unicode(255), nullable=False) voucher = relationship("Voucher", backref=backref("status", uselist=False)) @@ -80,13 +68,9 @@ class InventoryModifier(Base): __tablename__ = "inventory_modifiers" __table_args__ = (UniqueConstraint("inventory_id", "modifier_id"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - inventory_id = Column( - "inventory_id", GUID(), ForeignKey("inventories.id"), nullable=False - ) - modifier_id = Column( - "modifier_id", GUID(), ForeignKey("modifiers.id"), nullable=False - ) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + inventory_id = Column("inventory_id", UUID(as_uuid=True), ForeignKey("inventories.id"), nullable=False) + modifier_id = Column("modifier_id", UUID(as_uuid=True), ForeignKey("modifiers.id"), nullable=False) price = Column("price", Numeric, nullable=False) inventory = relationship("Inventory", backref="modifiers") @@ -102,44 +86,29 @@ class Voucher(Base): __tablename__ = "vouchers" __table_args__ = (UniqueConstraint("bill_id", "voucher_type"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) date = Column("date", DateTime, nullable=False, index=True) pax = Column("pax", Numeric, nullable=False) bill_id = Column("bill_id", Numeric) kot_id = Column("kot_id", Numeric, nullable=False, unique=True) creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) last_edit_date = Column("last_edit_date", DateTime(timezone=True), nullable=False) - food_table_id = Column( - "food_table_id", GUID(), ForeignKey("food_tables.id"), nullable=False - ) - customer_id = Column("customer_id", GUID(), ForeignKey("customers.id")) + food_table_id = Column("food_table_id", UUID(as_uuid=True), ForeignKey("food_tables.id"), nullable=False) + customer_id = Column("customer_id", UUID(as_uuid=True), ForeignKey("customers.id")) narration = Column("narration", Unicode(1000), nullable=False) reason = Column("reason", Unicode(255)) _voucher_type = Column("voucher_type", Integer, nullable=False) - user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) + user_id = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="vouchers") food_table = relationship("FoodTable", backref="vouchers") customer = relationship("Customer", backref="vouchers") - kots = relationship( - "Kot", - backref="voucher", - cascade="delete, delete-orphan", - cascade_backrefs=False, - ) + kots = relationship("Kot", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False,) settlements = relationship( - "Settlement", - backref="voucher", - cascade="delete, delete-orphan", - cascade_backrefs=False, - ) - reprints = relationship( - "Reprint", - backref="voucher", - cascade="delete, delete-orphan", - cascade_backrefs=False, + "Settlement", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False, ) + reprints = relationship("Reprint", backref="voucher", cascade="delete, delete-orphan", cascade_backrefs=False,) def _get_voucher_type(self): return VoucherType(self._voucher_type) @@ -151,15 +120,7 @@ class Voucher(Base): voucher_type = synonym("_voucher_type", descriptor=voucher_type) def __init__( - self, - date, - pax, - bill_id, - kot_id, - food_table_id, - customer_id, - voucher_type, - user_id, + self, date, pax, bill_id, kot_id, food_table_id, customer_id, voucher_type, user_id, ): self.date = date self.pax = pax @@ -196,28 +157,18 @@ class Voucher(Base): class Kot(Base): __tablename__ = "kots" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column( - "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True - ) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + voucher_id = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False, index=True) code = Column("code", Numeric, nullable=False, unique=True) - food_table_id = Column( - "food_table_id", GUID(), ForeignKey("food_tables.id"), nullable=False - ) + food_table_id = Column("food_table_id", UUID(as_uuid=True), ForeignKey("food_tables.id"), nullable=False) date = Column("date", DateTime, nullable=False, index=True) - user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) + user_id = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="kots") food_table = relationship("FoodTable", backref="kots") def __init__( - self, - voucher_id=None, - code=None, - food_table_id=None, - date=None, - user_id=None, - id_=None, + self, voucher_id=None, code=None, food_table_id=None, date=None, user_id=None, id_=None, ): self.id = id_ self.voucher_id = voucher_id @@ -231,10 +182,8 @@ class Settlement(Base): __tablename__ = "settlements" __table_args__ = (UniqueConstraint("voucher_id", "settled"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column( - "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True - ) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + voucher_id = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False, index=True) settled = Column("settled", ForeignKey("settle_options.id"), nullable=False) amount = Column("amount", Numeric, nullable=False) @@ -250,12 +199,10 @@ class Settlement(Base): class Reprint(Base): __tablename__ = "reprints" - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) date = Column("date", DateTime, nullable=False, index=True) - voucher_id = Column( - "voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False, index=True - ) - user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False) + voucher_id = Column("voucher_id", UUID(as_uuid=True), ForeignKey("vouchers.id"), nullable=False, index=True) + user_id = Column("user_id", UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) user = relationship("User", backref="reprints") @@ -268,18 +215,16 @@ class Reprint(Base): class Inventory(Base): __tablename__ = "inventories" - __table_args__ = ( - UniqueConstraint("kot_id", "product_id", "is_happy_hour", "price"), - ) + __table_args__ = (UniqueConstraint("kot_id", "product_id", "is_happy_hour", "price"),) - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - kot_id = Column("kot_id", GUID(), ForeignKey("kots.id"), nullable=False, index=True) - product_id = Column("product_id", GUID(), ForeignKey("products.id"), nullable=False) + id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + kot_id = Column("kot_id", UUID(as_uuid=True), ForeignKey("kots.id"), nullable=False, index=True) + product_id = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False) quantity = Column("quantity", Numeric) price = Column("price", Numeric) is_happy_hour = Column("is_happy_hour", Boolean, nullable=False) tax_rate = Column("tax_rate", Numeric) - tax_id = Column("tax_id", GUID(), ForeignKey("taxes.id"), nullable=False) + tax_id = Column("tax_id", UUID(as_uuid=True), ForeignKey("taxes.id"), nullable=False) discount = Column("discount", Numeric) sort_order = Column("sort_order", Numeric, nullable=False) @@ -288,16 +233,7 @@ class Inventory(Base): product = relationship("Product", backref="inventories") def __init__( - self, - kot_id, - product_id, - quantity, - price, - discount, - is_hh, - tax_id, - tax_rate, - sort_order, + self, kot_id, product_id, quantity, price, discount, is_hh, tax_id, tax_rate, sort_order, ): self.kot_id = kot_id self.product_id = product_id diff --git a/barker/renderers.py b/barker/renderers.py deleted file mode 100644 index 3491e54..0000000 --- a/barker/renderers.py +++ /dev/null @@ -1,57 +0,0 @@ -import csv -from decimal import Decimal -from io import StringIO -import uuid - -from pyramid.renderers import JSON - - - - -class CSVRenderer(object): - def __init__(self, info): - pass - - def __call__(self, value, system): - csv_data = StringIO() - writer = csv.writer(csv_data, delimiter=',', quoting=csv.QUOTE_MINIMAL) - - if 'header' in value: - writer.writerow(value['header']) - if 'rows' in value: - writer.writerows(value['rows']) - if 'footer' in value: - writer.writerows(value['footer']) - - request = system.get('request') - if request is not None: - response = request.response - ct = response.content_type - if ct == response.default_content_type: - response.content_type = 'text/csv' - filename = value['filename'] if 'filename' in value else 'report.csv' - response.content_disposition = 'attachment;filename="{0}"'.format(filename) - return csv_data.getvalue() - - -json_renderer = JSON() - - -class DecimalAsFloatHack(float): - def __init__(self, d): - self.d = d - - def __repr__(self): - return str(self.d) - - -def decimal_adaptor(obj, request): - return DecimalAsFloatHack(obj) - - -def uuid_adaptor(obj, request): - return str(obj) - - -json_renderer.add_adapter(Decimal, decimal_adaptor) -json_renderer.add_adapter(uuid.UUID, uuid_adaptor) diff --git a/barker/routers/__init__.py b/barker/routers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/barker/routers/auth/__init__.py b/barker/routers/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/barker/routers/auth/client.py b/barker/routers/auth/client.py new file mode 100644 index 0000000..4e47ef8 --- /dev/null +++ b/barker/routers/auth/client.py @@ -0,0 +1,108 @@ +import uuid + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy import desc +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ...schemas.auth import UserToken +from ...core.security import get_current_active_user as get_user +from ...db.session import SessionLocal +from ...models.auth import Client +import barker.schemas.auth as schemas + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.put("/{id_}") +def update( + id_: uuid.UUID, + data: schemas.ClientIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["clients"]), +): + try: + item: Client = db.query(Client).filter(Client.id == id_).first() + item.enabled = data.enabled + if item.enabled: + item.otp = None + item.name = data.name + db.commit() + return {} + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["clients"]), +): + try: + item: Client = db.query(Client).filter(Client.id == id_).first() + # db.execute(LoginHistory.__table__.delete(LoginHistory.client_id == item.id)) + db.delete(item) + db.commit() + return {} + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.get("/list") +async def show_list( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["clients"]), +): + list_ = db.query(Client).order_by(Client.name).all() + clients = [] + for item in list_: + # last_login = ( + # db.query(LoginHistory).filter(LoginHistory.client_id == item.id).order_by(desc(LoginHistory.date)).first() + # ) + # last_login = "Never" if last_login is None else last_login.date.strftime("%d-%b-%Y %H:%M") + last_login = "Never" + clients.append( + { + "id": item.id, + "code": item.code, + "name": item.name, + "enabled": item.enabled, + "otp": item.otp, + "creationDate": item.creation_date.strftime("%d-%b-%Y %H:%M"), + "lastLogin": last_login, + } + ) + return clients + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["clients"]), +): + item: Client = db.query(Client).filter(Client.id == id_).first() + return { + "id": item.id, + "code": item.code, + "name": item.name, + "enabled": item.enabled, + "otp": item.otp, + } diff --git a/barker/routers/auth/role.py b/barker/routers/auth/role.py new file mode 100644 index 0000000..2ee3375 --- /dev/null +++ b/barker/routers/auth/role.py @@ -0,0 +1,144 @@ +import uuid +from typing import List, Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ...schemas.auth import UserToken +from ...core.security import get_current_active_user as get_user +from ...db.session import SessionLocal +from ...models.auth import Role, Permission +import barker.schemas.auth as schemas + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("", response_model=schemas.Role) +def save( + data: schemas.RoleIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item = Role(data.name) + db.add(item) + add_permissions(item, data.permissions, db) + db.commit() + return role_info(item, db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.Role) +def update( + id_: uuid.UUID, + data: schemas.RoleIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item: Role = db.query(Role).filter(Role.id == id_).first() + item.name = data.name + add_permissions(item, data.permissions, db) + db.commit() + return role_info(item, db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +def add_permissions(role: Role, permissions: List[schemas.PermissionItem], db): + for permission in permissions: + gp = [p for p in role.permissions if p.id == permission.id_] + gp = None if len(gp) == 0 else gp[0] + if permission.enabled and gp is None: + role.permissions.append(db.query(Permission).filter(Permission.id == permission.id_).one()) + elif not permission.enabled and gp: + role.permissions.remove(gp) + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item: Role = db.query(Role).filter(Role.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Role not found", + ) + else: + raise HTTPException( + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Role deletion not implemented", + ) + except Exception: + db.rollback() + raise + + +@router.get("") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + return role_info(None, db) + + +@router.get("/list", response_model=List[schemas.RoleList]) +async def show_list( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + return [ + { + "id": item.id, + "name": item.name, + "permissions": [p.name for p in sorted(item.permissions, key=lambda p: p.name)], + } + for item in db.query(Role).order_by(Role.name).all() + ] + + +@router.get("/{id_}", response_model=schemas.Role) +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + item: Role = db.query(Role).filter(Role.id == id_).first() + return role_info(item, db) + + +def role_info(item: Optional[Role], db): + if item is None: + return { + "name": "", + "permissions": [ + {"id": p.id, "name": p.name, "enabled": False} + for p in db.query(Permission).order_by(Permission.name).all() + ], + } + else: + return { + "id": item.id, + "name": item.name, + "permissions": [ + {"id": p.id, "name": p.name, "enabled": True if p in item.permissions else False,} + for p in db.query(Permission).order_by(Permission.name).all() + ], + } diff --git a/barker/routers/auth/user.py b/barker/routers/auth/user.py new file mode 100644 index 0000000..79469f7 --- /dev/null +++ b/barker/routers/auth/user.py @@ -0,0 +1,187 @@ +import uuid +from typing import List, Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ...schemas.auth import UserToken +from ...core.security import get_current_active_user as get_user +from ...db.session import SessionLocal +from barker.models.auth import User, Role +import barker.schemas.auth as schemas + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("", response_model=schemas.User) +def save( + data: schemas.UserIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item = User(name=data.name, password=data.password, locked_out=data.locked_out) + db.add(item) + add_roles(item, data.roles, db) + db.commit() + return user_info(item, db, user) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.get("/me", response_model=schemas.User) +def show_me( + db: Session = Depends(get_db), user: UserToken = Depends(get_user), +): + item = db.query(User).filter(User.id == user.id_).first() + return user_info(item, db, user) + + +@router.put("/me", response_model=schemas.User) +def update_me( + data: schemas.UserIn, db: Session = Depends(get_db), user: UserToken = Depends(get_user), +): + try: + item: User = db.query(User).filter(User.id == user.id_).first() + if "users" in user.permissions: + item.name = data.name + item.locked_out = data.locked_out + add_roles(item, data.roles, db) + if data.password and item.password != data.password: + item.password = data.password + db.commit() + return user_info(item, db, user) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.User) +def update( + id_: uuid.UUID, + data: schemas.UserIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item: User = db.query(User).filter(User.id == id_).first() + item.name = data.name + if data.password and item.password != data.password: + item.password = data.password + item.locked_out = data.locked_out + add_roles(item, data.roles, db) + db.commit() + return user_info(item, db, user) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +def add_roles(user: User, roles: List[schemas.RoleItem], db: Session): + for role in roles: + ug = [g for g in user.roles if g.id == role.id_] + ug = None if len(ug) == 0 else ug[0] + if role.enabled and ug is None: + user.roles.append(db.query(Role).filter(Role.id == role.id_).one()) + elif not role.enabled and ug: + user.roles.remove(ug) + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + try: + item: User = db.query(User).filter(User.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="User not found", + ) + else: + raise HTTPException( + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="User deletion not implemented", + ) + except Exception: + db.rollback() + raise + + +@router.get("") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + return user_info(None, db, user) + + +@router.get("/list", response_model=List[schemas.UserList]) +async def show_list( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + return [ + { + "id": item.id, + "name": item.name, + "lockedOut": item.locked_out, + "roles": [p.name for p in sorted(item.roles, key=lambda p: p.name)], + } + for item in db.query(User).order_by(User.name).all() + ] + + +@router.get("/active") +async def show_active(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [{"name": item.name} for item in db.query(User).filter(User.locked_out == False).order_by(User.name)] + + +@router.get("/{id_}", response_model=schemas.User) +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["users"]), +): + item = db.query(User).filter(User.id == id_).first() + return user_info(item, db, user) + + +def user_info(item: Optional[User], db: Session, user: UserToken): + if item is None: + return { + "name": "", + "lockedOut": False, + "roles": [{"id": r.id, "name": r.name, "enabled": False} for r in db.query(Role).order_by(Role.name).all()], + } + else: + return { + "id": item.id, + "name": item.name, + "password": "", + "lockedOut": item.locked_out, + "roles": [ + {"id": r.id, "name": r.name, "enabled": True if r in item.roles else False} + for r in db.query(Role).order_by(Role.name).all() + ] + if "users" in user.permissions + else [], + } diff --git a/barker/routers/customer.py b/barker/routers/customer.py new file mode 100644 index 0000000..fe293d1 --- /dev/null +++ b/barker/routers/customer.py @@ -0,0 +1,86 @@ +import uuid + +import transaction +from pyramid.view import view_config + +from barker.models import Customer + + +@view_config( + request_method="PUT", route_name="v1_customers_new", renderer="json", permission="Customers", trans=True, +) +def save(request): + json = request.json_body + item = Customer(json["company"], json["name"], json["phone"], json["address"], json["important"]) + request.dbsession.add(item) + transaction.commit() + item = request.dbsession.query(Customer).filter(Customer.id == item.id).first() + return customer_info(item) + + +@view_config( + request_method="POST", route_name="v1_customers_id", renderer="json", permission="Customers", trans=True, +) +def update(request): + json = request.json_body + item = request.dbsession.query(Customer).filter(Customer.id == uuid.UUID(request.matchdict["id"])).first() + item.company = json["company"] + item.name = json["name"] + item.phone = json["phone"] + item.address = json["address"] + item.is_important = json["important"] + transaction.commit() + item = request.dbsession.query(Customer).filter(Customer.id == item.id).first() + return customer_info(item) + + +@view_config( + request_method="DELETE", route_name="v1_customers_id", renderer="json", permission="Customers", trans=True, +) +def delete(request): + item = request.dbsession.query(Customer).filter(Customer.id == uuid.UUID(request.matchdict["id"])).first() + request.dbsession.delete(item) + transaction.commit() + return {} + + +@view_config( + request_method="GET", route_name="v1_customers_id", renderer="json", permission="Authenticated", +) +def show_id(request): + id_ = uuid.UUID(request.matchdict["id"]) + item = request.dbsession.query(Customer).filter(Customer.id == id_).first() + return customer_info(item) + + +@view_config( + request_method="GET", route_name="v1_customers_list", renderer="json", permission="Authenticated", +) +def show_list(request): + list_ = request.dbsession.query(Customer).order_by(Customer.name).all() + customers = [] + for item in list_: + customers.append( + { + "id": item.id, + "company": item.company, + "name": item.name, + "address": item.address, + "important": item.is_important, + "phone": item.phone, + "remarks": "", + } + ) + return customers + + +def customer_info(item): + return { + "id": item.id, + "company": item.company, + "name": item.name, + "address": item.address, + "important": item.is_important, + "phone": item.phone, + "remarks": "", + } diff --git a/barker/views/device.py b/barker/routers/device.py similarity index 60% rename from barker/views/device.py rename to barker/routers/device.py index 48cb3ed..0ec5cd3 100644 --- a/barker/views/device.py +++ b/barker/routers/device.py @@ -8,11 +8,7 @@ from barker.models.validation_exception import ValidationError @view_config( - request_method="POST", - route_name="v1_devices_new", - renderer="json", - permission="Devices", - trans=True, + request_method="POST", route_name="v1_devices_new", renderer="json", permission="Devices", trans=True, ) def save(request): json = request.json_body @@ -30,23 +26,13 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_devices_id", - renderer="json", - permission="Devices", - trans=True, + request_method="PUT", route_name="v1_devices_id", renderer="json", permission="Devices", trans=True, ) def update(request): json = request.json_body - item = ( - request.dbsession.query(Device) - .filter(Device.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Device).filter(Device.id == uuid.UUID(request.matchdict["id"])).first() if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) + raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name)) item.name = json["name"].strip() item.section_id = uuid.UUID(json["section"]["id"]) transaction.commit() @@ -54,18 +40,10 @@ def update(request): @view_config( - request_method="DELETE", - route_name="v1_devices_id", - renderer="json", - permission="Devices", - trans=True, + request_method="DELETE", route_name="v1_devices_id", renderer="json", permission="Devices", trans=True, ) def delete(request): - item = ( - request.dbsession.query(Device) - .filter(Device.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Device).filter(Device.id == uuid.UUID(request.matchdict["id"])).first() if item is None: response = Response("Device not Found") response.status_int = 500 @@ -77,35 +55,25 @@ def delete(request): @view_config( - request_method="GET", - route_name="v1_devices_new", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_devices_new", renderer="json", permission="Authenticated", ) def show_blank(request): return device_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_devices_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_devices_id", renderer="json", permission="Authenticated", ) def show_id(request): return device_info(uuid.UUID(request.matchdict["id"]), request.dbsession) @view_config( - request_method="GET", - route_name="v1_devices_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_devices_list", renderer="json", permission="Authenticated", ) def show_list(request): return [ - device_info(item, request.dbsession) - for item in request.dbsession.query(Device).order_by(Device.name).all() + device_info(item, request.dbsession) for item in request.dbsession.query(Device).order_by(Device.name).all() ] diff --git a/barker/views/food_table.py b/barker/routers/food_table.py similarity index 67% rename from barker/views/food_table.py rename to barker/routers/food_table.py index ddfc6e9..1145057 100644 --- a/barker/views/food_table.py +++ b/barker/routers/food_table.py @@ -6,11 +6,7 @@ from barker.models.validation_exception import ValidationError @view_config( - request_method="POST", - route_name="v1_tables_new", - renderer="json", - permission="Tables", - trans=True, + request_method="POST", route_name="v1_tables_new", renderer="json", permission="Tables", trans=True, ) def save(request): json = request.json_body @@ -36,18 +32,10 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_tables_id", - renderer="json", - permission="Tables", - trans=True, + request_method="PUT", route_name="v1_tables_id", renderer="json", permission="Tables", trans=True, ) def update(request): - item = ( - request.dbsession.query(FoodTable) - .filter(FoodTable.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(FoodTable).filter(FoodTable.id == uuid.UUID(request.matchdict["id"])).first() json = request.json_body item.name = json["name"].strip() if item.name == "": @@ -65,65 +53,41 @@ def update(request): @view_config( - request_method="DELETE", - route_name="v1_tables_id", - renderer="json", - permission="Tables", - trans=True, + request_method="DELETE", route_name="v1_tables_id", renderer="json", permission="Tables", trans=True, ) def delete(request): - item = ( - request.dbsession.query(FoodTable) - .filter(FoodTable.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(FoodTable).filter(FoodTable.id == uuid.UUID(request.matchdict["id"])).first() request.dbsession.delete(item) transaction.commit() return {None, request.dbsession} @view_config( - request_method="GET", - route_name="v1_tables_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_tables_id", renderer="json", permission="Authenticated", ) def show_id(request): id_ = uuid.UUID(request.matchdict["id"]) return food_table_info(id_, request.dbsession) -@view_config( - request_method="GET", route_name="v1_tables_new", renderer="json", request_param="v" -) +@view_config(request_method="GET", route_name="v1_tables_new", renderer="json", request_param="v") def show_voucher(request): voucher_id = request.GET["v"] - voucher = ( - request.dbsession.query(Overview) - .filter(Overview.voucher_id == voucher_id) - .first() - ) + voucher = request.dbsession.query(Overview).filter(Overview.voucher_id == voucher_id).first() if voucher is not None: return food_table_info(voucher.food_table, request.dbsession) return {} @view_config( - request_method="GET", - route_name="v1_tables_new", - renderer="json", - permission="Tables", + request_method="GET", route_name="v1_tables_new", renderer="json", permission="Tables", ) def show_blank(request): return food_table_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_tables_list", - renderer="json", - request_param="r", - permission="Authenticated", + request_method="GET", route_name="v1_tables_list", renderer="json", request_param="r", permission="Authenticated", ) def show_running(request): list_ = request.dbsession.query(FoodTable).filter(FoodTable.is_active == True).order_by(FoodTable.sort_order).all() @@ -136,7 +100,7 @@ def show_running(request): "seats": item.seats, "section": {"id": item.section_id, "name": item.section.name}, "isActive": item.is_active, - "sortOrder": item.sort_order + "sortOrder": item.sort_order, } if item.status is not None: ft["status"] = item.status.status @@ -151,34 +115,31 @@ def show_running(request): @view_config( - request_method="GET", - route_name="v1_tables_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_tables_list", renderer="json", permission="Authenticated", ) def show_list(request): - return [{ - "id": item.id, - "name": item.name, - "seats": item.seats, - "section": {"id": item.section_id, "name": item.section.name}, - "isActive": item.is_active, - "sortOrder": item.sort_order - } for item in request.dbsession.query(FoodTable).order_by(FoodTable.sort_order).all()] + return [ + { + "id": item.id, + "name": item.name, + "seats": item.seats, + "section": {"id": item.section_id, "name": item.section.name}, + "isActive": item.is_active, + "sortOrder": item.sort_order, + } + for item in request.dbsession.query(FoodTable).order_by(FoodTable.sort_order).all() + ] @view_config( - request_method="POST", - route_name="v1_tables_list", - renderer="json", - permission="Tables", + request_method="POST", route_name="v1_tables_list", renderer="json", permission="Tables", ) def sort_order(request): json = request.json_body for index, item in enumerate(json): - request.dbsession.query(FoodTable).filter( - FoodTable.id == uuid.UUID(item["id"]) - ).update({FoodTable.sort_order: index}) + request.dbsession.query(FoodTable).filter(FoodTable.id == uuid.UUID(item["id"])).update( + {FoodTable.sort_order: index} + ) return True @@ -191,7 +152,7 @@ def food_table_info(item, dbsession): "id": item.id, "name": item.name, "seats": item.seats, - "section": {"id": item.section_id, "name":item.section.name}, + "section": {"id": item.section_id, "name": item.section.name}, "isActive": item.is_active, "status": "" if item.status is None else item.status.status, "sortOrder": item.sort_order, diff --git a/barker/views/guest_book.py b/barker/routers/guest_book.py similarity index 73% rename from barker/views/guest_book.py rename to barker/routers/guest_book.py index 42e07be..81e476b 100644 --- a/barker/views/guest_book.py +++ b/barker/routers/guest_book.py @@ -8,11 +8,7 @@ from barker.models import GuestBook, Customer @view_config( - request_method="PUT", - route_name="v1_guest_book_new", - renderer="json", - permission="Guest Book", - trans=True, + request_method="PUT", route_name="v1_guest_book_new", renderer="json", permission="Guest Book", trans=True, ) def save(request): json = request.json_body @@ -40,34 +36,23 @@ def save(request): @view_config( - request_method="GET", - route_name="v1_guest_book_id", - renderer="json", - permission="Guest Book", + request_method="GET", route_name="v1_guest_book_id", renderer="json", permission="Guest Book", ) def show_id(request): id_ = request.matchdict["id"] - item = ( - request.dbsession.query(GuestBook).filter(GuestBook.id == uuid.UUID(id_)).one() - ) + item = request.dbsession.query(GuestBook).filter(GuestBook.id == uuid.UUID(id_)).one() return guest_book_info(item) @view_config( - request_method="GET", - route_name="v1_guest_book_new", - renderer="json", - permission="Guest Book", + request_method="GET", route_name="v1_guest_book_new", renderer="json", permission="Guest Book", ) def show_blank(request): return guest_book_info(None) @view_config( - request_method="GET", - route_name="v1_guest_book_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_guest_book_list", renderer="json", permission="Authenticated", ) def show_list(request): date_ = request.GET.get("q", None) @@ -76,16 +61,9 @@ def show_list(request): list_ = ( request.dbsession.query(GuestBook) .filter( - GuestBook.date - >= datetime.strptime(date_, "%d-%b-%Y") - - timedelta(minutes=30) # hack for timezone and 5 am - ) - .filter( - GuestBook.date - < datetime.strptime(date_, "%d-%b-%Y") - - timedelta(minutes=30) - + timedelta(days=1) + GuestBook.date >= datetime.strptime(date_, "%d-%b-%Y") - timedelta(minutes=30) # hack for timezone and 5 am ) + .filter(GuestBook.date < datetime.strptime(date_, "%d-%b-%Y") - timedelta(minutes=30) + timedelta(days=1)) .order_by(GuestBook.date) .all() ) diff --git a/barker/routers/login.py b/barker/routers/login.py new file mode 100644 index 0000000..20e2af9 --- /dev/null +++ b/barker/routers/login.py @@ -0,0 +1,87 @@ +from datetime import timedelta + +from fastapi import ( + APIRouter, + Depends, + HTTPException, + status, + Security, + Cookie, + Form, + Response, +) +from fastapi.security import OAuth2PasswordRequestForm +from fastapi.responses import JSONResponse +from sqlalchemy.orm import Session +from ..core.security import ( + Token, + authenticate_user, + create_access_token, + get_current_active_user, + client_allowed, +) +from barker.core.config import settings +from ..db.session import SessionLocal +from ..schemas.auth import UserToken + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/token", response_model=Token) +async def login_for_access_token( + response: Response, + form_data: OAuth2PasswordRequestForm = Depends(), + client_id: int = Cookie(None), + otp: int = Form(None), + db: Session = Depends(get_db), +): + user = authenticate_user(form_data.username, form_data.password, client_id, otp, db) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + allowed, c_id = client_allowed(user, client_id, otp, db) + db.commit() + if c_id and c_id != client_id: + response.set_cookie(key="client_id", value=str(c_id), max_age=10 * 365 * 24 * 60 * 60) + if not allowed: + not_allowed_response = JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + headers={"WWW-Authenticate": "Bearer"}, + content={"detail": "Client is not registered"}, + ) + not_allowed_response.set_cookie(key="client_id", value=str(c_id), max_age=10 * 365 * 24 * 60 * 60) + return not_allowed_response + access_token_expires = timedelta(minutes=settings.JWT_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={ + "sub": user.name, + "scopes": ["authenticated"] + + list(set([p.name.replace(" ", "-").lower() for r in user.roles for p in r.permissions])), + "userId": str(user.id), + "lockedOut": user.locked_out, + }, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} + + +@router.post("/refresh", response_model=Token) +async def refresh_token(user: UserToken = Security(get_current_active_user)): + access_token_expires = timedelta(minutes=settings.JWT_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.name, "scopes": user.permissions, "userId": str(user.id_), "lockedOut": user.locked_out,}, + expires_delta=access_token_expires, + ) + return {"access_token": access_token, "token_type": "bearer"} diff --git a/barker/routers/menu_category.py b/barker/routers/menu_category.py new file mode 100644 index 0000000..1925874 --- /dev/null +++ b/barker/routers/menu_category.py @@ -0,0 +1,188 @@ +import uuid +from typing import Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ..schemas.auth import UserToken +import barker.schemas.master as schemas +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal +from ..models.master import Product, MenuCategory + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/", response_model=schemas.MenuCategory) +def save( + data: schemas.MenuCategoryIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item = MenuCategory(name=data.name, discount_limit=data.discount_limit, is_active=data.is_active, sort_order=0) + db.add(item) + db.commit() + return menu_category_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.MenuCategory) +def update( + id_: uuid.UUID, + data: schemas.MenuCategoryIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: MenuCategory = db.query(MenuCategory).filter(MenuCategory.id == id_).first() + if item.is_fixture: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", + ) + item.name = data.name + item.discount_limit = data.discount_limit + item.is_active = data.discount_limit + db.commit() + return menu_category_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: MenuCategory = db.query(MenuCategory).filter(MenuCategory.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Menu Category not found", + ) + elif item.is_fixture: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", + ) + else: + raise HTTPException( + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Menu Category deletion not implemented", + ) + except Exception: + db.rollback() + raise + + +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + return menu_category_info(None) + + +@router.get("/list") +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [menu_category_info(item) for item in db.query(MenuCategory).order_by(MenuCategory.sort_order).order_by(MenuCategory.name).all()] + + +@router.get("/sale-list") +async def sale_list( + db: Session = Depends(get_db), + current_user: UserToken = Depends(get_user), +): + list_ = ( + db.query(MenuCategory) + .filter(MenuCategory.is_active == True) + .order_by(MenuCategory.sort_order) + .order_by(MenuCategory.name) + .all() + ) + menu_categories = [] + for item in list_: + products = ( + db.query(Product) + .filter(Product.menu_category_id == item.id) + .filter(Product.is_active == True) + .order_by(Product.sort_order) + .order_by(Product.name) + .all() + ) + if len(products) == 0: + continue + pg = menu_category_info(item) + pg["products"] = [ + { + "id": p.id, + "name": p.name, + "units": p.units, + "tat": {"id": p.vat.id, "name": p.vat.name, "rate": p.vat.rate}, + "price": p.price, + "hasHappyHour": p.has_happy_hour, + "isActive": p.is_active, + "isNotAvailable": p.is_not_available, + "sortOrder": p.sort_order, + "quantity": p.quantity, + } + for p in products + ] + menu_categories.append(pg) + return menu_categories + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + item: MenuCategory = db.query(MenuCategory).filter(MenuCategory.id == id_).first() + return menu_category_info(item) + + +# @view_config( +# request_method="POST", route_name="v1_menu_categories_list", renderer="json", permission="Products", trans=True, +# ) +# def sort_order(request): +# json = request.json_body +# for index, item in enumerate(json): +# request.dbsession.query(MenuCategory).filter(MenuCategory.id == uuid.UUID(item["id"])).update( +# {MenuCategory.sort_order: index} +# ) +# return True + + +def menu_category_info(item: Optional[MenuCategory]): + if item is None: + return { + "name": "", + "discountLimit": 0, + "isActive": True, + "isFixture": False, + "sortOrder": 0, + } + return { + "id": item.id, + "name": item.name, + "discountLimit": item.discount_limit * 100, + "isActive": item.is_active, + "isFixture": item.is_fixture, + "sortOrder": item.sort_order, + } diff --git a/barker/views/modifier.py b/barker/routers/modifier.py similarity index 68% rename from barker/views/modifier.py rename to barker/routers/modifier.py index 41d1765..f754adf 100644 --- a/barker/views/modifier.py +++ b/barker/routers/modifier.py @@ -10,11 +10,7 @@ from barker.models.validation_exception import ValidationError @view_config( - request_method="POST", - route_name="v1_modifiers_new", - renderer="json", - permission="Modifiers", - trans=True, + request_method="POST", route_name="v1_modifiers_new", renderer="json", permission="Modifiers", trans=True, ) def save(request): json = request.json_body @@ -42,18 +38,10 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_modifiers_id", - renderer="json", - permission="Modifiers", - trans=True, + request_method="PUT", route_name="v1_modifiers_id", renderer="json", permission="Modifiers", trans=True, ) def update(request): - item = ( - request.dbsession.query(Modifier) - .filter(Modifier.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Modifier).filter(Modifier.id == uuid.UUID(request.matchdict["id"])).first() json = request.json_body item.name = json["name"].strip() if item.name == "": @@ -72,38 +60,24 @@ def update(request): @view_config( - request_method="DELETE", - route_name="v1_modifiers_id", - renderer="json", - permission="Modifiers", - trans=True, + request_method="DELETE", route_name="v1_modifiers_id", renderer="json", permission="Modifiers", trans=True, ) def delete(request): - item = ( - request.dbsession.query(Modifier) - .filter(Modifier.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Modifier).filter(Modifier.id == uuid.UUID(request.matchdict["id"])).first() request.dbsession.delete(item) transaction.commit() return {} @view_config( - request_method="GET", - route_name="v1_modifiers_new", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_modifiers_new", renderer="json", permission="Authenticated", ) def show_blank(request): return modifier_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_modifiers_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_modifiers_id", renderer="json", permission="Authenticated", ) def show_id(request): id_ = uuid.UUID(request.matchdict["id"]) @@ -111,10 +85,7 @@ def show_id(request): @view_config( - request_method="GET", - route_name="v1_modifiers_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_modifiers_list", renderer="json", permission="Authenticated", ) def show_list(request): return [ @@ -125,7 +96,13 @@ def show_list(request): def modifier_info(item, dbsession): if item is None: - return {"name": "", "showInBill": False, "price": 0, "isActive": True, "modifierCategory": {}} + return { + "name": "", + "showInBill": False, + "price": 0, + "isActive": True, + "modifierCategory": {}, + } if type(item) is uuid.UUID: item = dbsession.query(Modifier).filter(Modifier.id == item).first() return { @@ -134,8 +111,5 @@ def modifier_info(item, dbsession): "showInBill": item.show_in_bill, "price": item.price, "isActive": item.is_active, - "modifierCategory": { - "id": item.modifier_category.id, - "name": item.modifier_category.name, - }, + "modifierCategory": {"id": item.modifier_category.id, "name": item.modifier_category.name,}, } diff --git a/barker/routers/modifier_category.py b/barker/routers/modifier_category.py new file mode 100644 index 0000000..ca424a1 --- /dev/null +++ b/barker/routers/modifier_category.py @@ -0,0 +1,219 @@ +import uuid +from functools import reduce +from typing import Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ..schemas.auth import UserToken +import barker.schemas.master as schemas +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal +from ..models.master import ModifierCategory, MenuCategory, Product + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/", response_model=schemas.ModifierCategory) +def save( + data: schemas.ModifierCategoryIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["modifiers"]), +): + try: + item = ModifierCategory(name=data.name, minimum=data.minimum, maximum=data.maximum, is_active=data.is_active) + db.add(item) + add_products(item, data.menu_categories, db) + db.commit() + return modifier_category_info(item, db=db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.ModifierCategory) +def update( + id_: uuid.UUID, + data: schemas.ModifierCategoryIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["modifiers"]), +): + try: + item: ModifierCategory = db.query(ModifierCategory).filter(ModifierCategory.id == id_).first() + item.name = data.name + item.minimum = data.minimum + item.maximum = data.maximum + item.is_active = data.is_active + add_products(item, data.menu_categories, db) + db.commit() + return modifier_category_info(item, db=db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["modifiers"]), +): + try: + item: ModifierCategory = db.query(ModifierCategory).filter(ModifierCategory.id == id_).first() + db.delete(item) + db.commit() + return modifier_category_info(None, db=db) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["modifiers"]), +): + return modifier_category_info(None, db=db) + + +@router.get("/list") +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + list_ = db.query(ModifierCategory).order_by(ModifierCategory.sort_order).order_by(ModifierCategory.name).all() + menu_categories = ( + db.query(MenuCategory) + .join(MenuCategory.products) + .filter(Product.is_active == True) + .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) + .all() + ) + modifier_categories = [] + for item in list_: + modifier_category = { + "id": item.id, + "name": item.name, + "minimum": item.minimum, + "maximum": item.maximum, + "isActive": item.is_active, + "menuCategories": [ + { + "id": mc.id, + "name": mc.name, + "enabled": reduce(lambda x, y: x and (y in item.products), mc.products, True), + "products": [{"id": p.id, "name": p.name} for p in mc.products if p in item.products], + } + for mc in menu_categories + ], + } + modifier_category["menuCategories"] = [i for i in modifier_category["menuCategories"] if len(i["products"]) > 0] + modifier_categories.append(modifier_category) + return modifier_categories + + +@router.get("/for-product/{id_}") +def for_product( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user), +): + product: Product = db.query(Product).filter(Product.id == id_).first() + + return [ + { + "id": item.id, + "name": item.name, + "minimum": item.minimum, + "maximum": item.maximum, + "isActive": item.is_active, + "modifiers": [ + {"id": m.id, "name": m.name, "price": m.price} for m in item.modifiers if m.is_active == True + ], + } + for item in product.modifier_categories + if item.is_active == True + ] + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["modifiers"]), +): + item: ModifierCategory = db.query(ModifierCategory).filter(ModifierCategory.id == id_).first() + return modifier_category_info(item, db=db) + + +def modifier_category_info(item: Optional[ModifierCategory], db: Session): + menu_categories = ( + db.query(MenuCategory) + .join(MenuCategory.products) + .filter(Product.is_active == True) + .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) + .all() + ) + if item is None: + return { + "name": "", + "minimum": 0, + "maximum": 0, + "isActive": True, + "menuCategories": [ + { + "id": mc.id, + "name": mc.name, + "enabled": False, + "products": [{"id": p.id, "name": p.name, "enabled": False} for p in mc.products], + } + for mc in menu_categories + ], + "sortOrder": item.sort_order, + } + return { + "id": item.id, + "name": item.name, + "minimum": item.minimum, + "maximum": item.maximum, + "isActive": item.is_active, + "menuCategories": [ + { + "id": mc.id, + "name": mc.name, + "enabled": False, + "products": [ + {"id": p.id, "name": p.name, "enabled": True if p in item.products else False} for p in mc.products + ], + } + for mc in menu_categories + ], + "sortOrder": item.sort_order, + } + + +def add_products(modifier_category: ModifierCategory, menu_categories, db: Session): + for mc in menu_categories: + for p in mc.products: + old = [x for x in modifier_category.products if x.id == p.id_] + old = None if len(old) == 0 else old[0] + if p.enabled and old is None: + product_object = db.query(Product).filter(Product.id == p.id_).one() + modifier_category.products.append(product_object) + elif not p.enabled and old: + modifier_category.products.remove(old) diff --git a/barker/views/printer.py b/barker/routers/printer.py similarity index 61% rename from barker/views/printer.py rename to barker/routers/printer.py index 5fec34f..6ac1f52 100644 --- a/barker/views/printer.py +++ b/barker/routers/printer.py @@ -7,11 +7,7 @@ from barker.models.validation_exception import ValidationError @view_config( - request_method="POST", - route_name="v1_printers_new", - renderer="json", - permission="Printers", - trans=True, + request_method="POST", route_name="v1_printers_new", renderer="json", permission="Printers", trans=True, ) def save(request): json = request.json_body @@ -29,19 +25,11 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_printers_id", - renderer="json", - permission="Printers", - trans=True, + request_method="PUT", route_name="v1_printers_id", renderer="json", permission="Printers", trans=True, ) def update(request): json = request.json_body - item = ( - request.dbsession.query(Printer) - .filter(Printer.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Printer).filter(Printer.id == uuid.UUID(request.matchdict["id"])).first() item.name = json.get("name", "").strip() if item.name == "": raise ValidationError("Name cannot be blank") @@ -54,64 +42,40 @@ def update(request): @view_config( - request_method="DELETE", - route_name="v1_printers_id", - renderer="json", - permission="Printers", - trans=True, + request_method="DELETE", route_name="v1_printers_id", renderer="json", permission="Printers", trans=True, ) def delete(request): - item = ( - request.dbsession.query(Printer) - .filter(Printer.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Printer).filter(Printer.id == uuid.UUID(request.matchdict["id"])).first() if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) + raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name)) request.dbsession.delete(item) transaction.commit() return printer_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_printers_new", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_printers_new", renderer="json", permission="Authenticated", ) def show_blank(request): return printer_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_printers_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_printers_id", renderer="json", permission="Authenticated", ) def show_id(request): return printer_info(uuid.UUID(request.matchdict["id"]), request.dbsession) @view_config( - request_method="GET", - route_name="v1_printers_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_printers_list", renderer="json", permission="Authenticated", ) def show_list(request): list_ = request.dbsession.query(Printer).order_by(Printer.name).all() printers = [] for item in list_: printers.append( - { - "id": item.id, - "name": item.name, - "address": item.address, - "cutCode": item.cut_code, - } + {"id": item.id, "name": item.name, "address": item.address, "cutCode": item.cut_code,} ) return printers diff --git a/barker/routers/product.py b/barker/routers/product.py new file mode 100644 index 0000000..7911793 --- /dev/null +++ b/barker/routers/product.py @@ -0,0 +1,241 @@ +import uuid +from typing import Optional, List + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session, joinedload + +from ..schemas.auth import UserToken +import barker.schemas.master as schemas +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal +from ..models.master import Product + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/list", response_model=List[schemas.Product]) +def sort_order( + data: List[schemas.Product], db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["products"]), +): + try: + indexes = {} + for item in data: + if item.menu_category.id_ in indexes: + indexes[item.menu_category.id_] += 1 + else: + indexes[item.menu_category.id_] = 0 + db.query(Product).filter(Product.id == item.id_).update( + {Product.sort_order: indexes[item.menu_category.id_]} + ) + db.commit() + return [ + product_info(item) + for item in db.query(Product) + .order_by(Product.menu_category_id) + .order_by(Product.sort_order) + .order_by(Product.name) + .options(joinedload(Product.menu_category), joinedload(Product.sale_category)) + .all() + ] + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.post("/", response_model=schemas.Product) +def save( + data: schemas.ProductIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item = Product( + name=data.name, + units=data.units, + menu_category_id=data.menu_category.id_, + sale_category_id=data.sale_category.id_, + price=data.price, + has_happy_hour=data.has_happy_hour, + is_not_available=data.is_not_available, + quantity=data.quantity, + is_active=data.is_active, + ) + db.add(item) + db.commit() + return product_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.Product) +def update( + id_: uuid.UUID, + data: schemas.ProductIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: Product = db.query(Product).filter(Product.id == id_).first() + item.name = data.name + item.units = data.units + item.menu_category_id = data.menu_category.id_ + item.sale_category_id = data.sale_category.id_ + item.price = data.price + item.has_happy_hour = data.has_happy_hour + item.is_not_available = data.is_not_available + item.quantity = data.quantity + item.is_active = data.is_active + db.commit() + return product_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: Product = db.query(Product).filter(Product.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Product not found", + ) + else: + raise HTTPException( + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Product deletion not implemented", + ) + except Exception: + db.rollback() + raise + + +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + return product_info(None) + + +@router.get("/list") +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [ + product_info(item) + for item in db.query(Product) + .order_by(Product.menu_category_id) + .order_by(Product.sort_order) + .order_by(Product.name) + .options(joinedload(Product.menu_category), joinedload(Product.sale_category)) + .all() + ] + + +@router.get("/query") +async def show_term( + mc: uuid.UUID = None, + a: bool = None, + db: Session = Depends(get_db), + current_user: UserToken = Depends(get_user), +): + list_ = [] + for item in db.query(Product).filter(Product.is_active == a, Product.menu_category_id == mc).order_by(Product.sort_order, Product.name).all(): + list_.append( + { + "id": item.id, + "name": item.full_name, + "saleCategory": {"id": item.sale_category_id, "name": item.sale_category.name, }, + "tax": { + "id": item.sale_category.tax_id, + "name": item.sale_category.tax.name, + "rate": item.sale_category.tax.rate, + }, + "price": item.price, + "hasHappyHour": False, + "isNotAvailable": item.is_not_available, + "isActive": item.is_active, + "sortOrder": item.sort_order, + } + ) + if item.has_happy_hour: + list_.append( + { + "id": item.id, + "name": "H H " + item.full_name, + "saleCategory": {"id": item.sale_category_id, "name": item.sale_category.name, }, + "tax": { + "id": item.sale_category.tax_id, + "name": item.sale_category.tax.name, + "rate": item.sale_category.tax.rate, + }, + "price": item.price, + "hasHappyHour": True, + "isNotAvailable": item.is_not_available, + "isActive": item.is_active, + "sortOrder": item.sort_order, + } + ) + return list_ + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + item: Product = db.query(Product).filter(Product.id == id_).first() + return product_info(item) + + +def product_info(item: Optional[Product]): + if item is None: + return { + "name": "", + "units": "", + "menuCategory": {}, + "saleCategory": {}, + "price": 0, + "hasHappyHour": False, + "isNotAvailable": False, + "isActive": True, + "sortOrder": 0, + } + return { + "id": item.id, + "name": item.name, + "units": item.units, + "menuCategory": {"id": item.menu_category_id, "name": item.menu_category.name}, + "saleCategory": { + "id": item.sale_category_id, + "name": item.sale_category.name, + }, + "price": item.price, + "hasHappyHour": item.has_happy_hour, + "isNotAvailable": item.is_not_available, + "isActive": item.is_active, + "sortOrder": item.sort_order, + } diff --git a/barker/views/reports/__init__.py b/barker/routers/reports/__init__.py similarity index 100% rename from barker/views/reports/__init__.py rename to barker/routers/reports/__init__.py diff --git a/barker/views/reports/beer_consumption_report.py b/barker/routers/reports/beer_consumption_report.py similarity index 91% rename from barker/views/reports/beer_consumption_report.py rename to barker/routers/reports/beer_consumption_report.py index 3e83000..338e1b1 100644 --- a/barker/views/reports/beer_consumption_report.py +++ b/barker/routers/reports/beer_consumption_report.py @@ -34,11 +34,7 @@ def beer_consumption(request): day >= start_date, day <= finish_date, Voucher.voucher_type.in_( - [ - VoucherType.REGULAR_BILL.value, - VoucherType.NO_CHARGE.value, - VoucherType.STAFF.value, - ] + [VoucherType.REGULAR_BILL.value, VoucherType.NO_CHARGE.value, VoucherType.STAFF.value,] ), ) .group_by(day, Product.name) diff --git a/barker/views/reports/bill_settlement_report.py b/barker/routers/reports/bill_settlement_report.py similarity index 83% rename from barker/views/reports/bill_settlement_report.py rename to barker/routers/reports/bill_settlement_report.py index 319e08b..be46a3f 100644 --- a/barker/views/reports/bill_settlement_report.py +++ b/barker/routers/reports/bill_settlement_report.py @@ -8,10 +8,7 @@ from barker.views.reports import get_start_date, get_finish_date @view_config( - request_method="GET", - route_name="v1_bill_settlement_report", - renderer="json", - permission="Bill Settlement Report", + request_method="GET", route_name="v1_bill_settlement_report", renderer="json", permission="Bill Settlement Report", ) def bill_details(request): start_date = get_start_date(request.GET.get("s", None)) @@ -70,16 +67,8 @@ def reprints(start_date, finish_date, dbsession): "billId": item.voucher.full_bill_id, "settlement": f"Reprinted by {item.user.name}", "Amount": round( - next( - s.amount - for s in item.voucher.settlements - if s.settled == SettleOption.AMOUNT() - ) - * -1, - 2, + next(s.amount for s in item.voucher.settlements if s.settled == SettleOption.AMOUNT()) * -1, 2, ), } - for item in dbsession.query(Reprint) - .filter(Reprint.date >= start_date, Reprint.date <= finish_date) - .all() + for item in dbsession.query(Reprint).filter(Reprint.date >= start_date, Reprint.date <= finish_date).all() ] diff --git a/barker/views/reports/cashier_report.py b/barker/routers/reports/cashier_report.py similarity index 78% rename from barker/views/reports/cashier_report.py rename to barker/routers/reports/cashier_report.py index 5459faa..6871aec 100644 --- a/barker/views/reports/cashier_report.py +++ b/barker/routers/reports/cashier_report.py @@ -11,10 +11,7 @@ __author__ = "tanshu" @view_config( - request_method="GET", - route_name="v1_active_cashiers", - renderer="json", - permission="Cashier Report", + request_method="GET", route_name="v1_active_cashiers", renderer="json", permission="Cashier Report", ) def active_cashiers(request): start_date = get_start_date(request.GET.get("s", None)) @@ -26,21 +23,13 @@ def active_cashiers(request): .distinct() ) - users = ( - request.dbsession.query(User) - .filter(User.id.in_(user_ids)) - .order_by(User.name) - .all() - ) + users = request.dbsession.query(User).filter(User.id.in_(user_ids)).order_by(User.name).all() return [{"id": u.id, "name": u.name} for u in users] @view_config( - request_method="GET", - route_name="v1_cashier_report", - renderer="json", - permission="Cashier Report", + request_method="GET", route_name="v1_cashier_report", renderer="json", permission="Cashier Report", ) def blank_out(request): start_date = request.GET.get("s", datetime.today().strftime("%d-%b-%Y")) @@ -69,16 +58,8 @@ def check_me_out(request): vouchers = ( request.dbsession.query(Voucher) - .options( - joinedload(Voucher.settlements, innerjoin=True).joinedload( - Settlement.settle_option, innerjoin=True - ) - ) - .filter( - Voucher.date >= start_date, - Voucher.date <= finish_date, - Voucher.user_id == id_, - ) + .options(joinedload(Voucher.settlements, innerjoin=True).joinedload(Settlement.settle_option, innerjoin=True)) + .filter(Voucher.date >= start_date, Voucher.date <= finish_date, Voucher.user_id == id_,) .order_by(Voucher.voucher_type) .order_by(Voucher.bill_id) .all() diff --git a/barker/views/reports/discount_report.py b/barker/routers/reports/discount_report.py similarity index 80% rename from barker/views/reports/discount_report.py rename to barker/routers/reports/discount_report.py index bdc3dd8..dfcb73e 100644 --- a/barker/views/reports/discount_report.py +++ b/barker/routers/reports/discount_report.py @@ -9,10 +9,7 @@ from barker.views.reports import get_start_date, get_finish_date @view_config( - request_method="GET", - route_name="v1_discount_report", - renderer="json", - permission="Discount Report", + request_method="GET", route_name="v1_discount_report", renderer="json", permission="Discount Report", ) def discount_report_view(request): start_date = get_start_date(request.GET.get("s", None)) @@ -31,9 +28,7 @@ def discount_report_view(request): def discount_report(start_date, finish_date, dbsession): - amount = func.sum( - Inventory.quantity * Inventory.effective_price * Inventory.discount - ).label("Amount") + amount = func.sum(Inventory.quantity * Inventory.effective_price * Inventory.discount).label("Amount") list_ = ( dbsession.query(SaleCategory.name, amount) .join(Voucher.kots) @@ -44,9 +39,7 @@ def discount_report(start_date, finish_date, dbsession): Inventory.discount != 0, Voucher.date >= start_date, Voucher.date <= finish_date, - Voucher.voucher_type.in_( - [VoucherType.REGULAR_BILL.value, VoucherType.KOT.value] - ), + Voucher.voucher_type.in_([VoucherType.REGULAR_BILL.value, VoucherType.KOT.value]), ) .group_by(SaleCategory.name) .order_by(SaleCategory.name) diff --git a/barker/views/reports/product_sale_report.py b/barker/routers/reports/product_sale_report.py similarity index 81% rename from barker/views/reports/product_sale_report.py rename to barker/routers/reports/product_sale_report.py index 6a8bfa1..aeccc8b 100644 --- a/barker/views/reports/product_sale_report.py +++ b/barker/routers/reports/product_sale_report.py @@ -16,10 +16,7 @@ from barker.views.reports import get_start_date, get_finish_date @view_config( - request_method="GET", - route_name="v1_product_sale_report", - renderer="json", - permission="Product Sale Report", + request_method="GET", route_name="v1_product_sale_report", renderer="json", permission="Product Sale Report", ) def product_sale_report_view(request): start_date = get_start_date(request.GET.get("s", None)) @@ -40,11 +37,7 @@ def product_sale_report_view(request): def product_sale_report(start_date, finish_date, dbsession): list_ = ( dbsession.query( - Product.id, - Product.full_name, - Voucher.voucher_type, - Inventory.is_happy_hour, - func.sum(Inventory.quantity), + Product.id, Product.full_name, Voucher.voucher_type, Inventory.is_happy_hour, func.sum(Inventory.quantity), ) .join(Inventory.kot) .join(Kot.voucher) @@ -71,12 +64,7 @@ def product_sale_report(start_date, finish_date, dbsession): old[0][type_] = quantity else: info.append( - { - "id": id_, - "name": "H H " + name if hh else name, - "isHappyHour": hh, - type_: quantity, - } + {"id": id_, "name": "H H " + name if hh else name, "isHappyHour": hh, type_: quantity,} ) return info diff --git a/barker/views/reports/sale_report.py b/barker/routers/reports/sale_report.py similarity index 90% rename from barker/views/reports/sale_report.py rename to barker/routers/reports/sale_report.py index 9184c95..8bb1a81 100644 --- a/barker/views/reports/sale_report.py +++ b/barker/routers/reports/sale_report.py @@ -18,10 +18,7 @@ from barker.views.reports import get_start_date, get_finish_date @view_config( - request_method="GET", - route_name="v1_sale_report", - renderer="json", - permission="Sale Report", + request_method="GET", route_name="v1_sale_report", renderer="json", permission="Sale Report", ) def get_sale_analysis(request): start_date = get_start_date(request.GET.get("s", None)) @@ -88,10 +85,7 @@ def get_settlements(start_date, finish_date, dbsession): @view_config( - request_method="GET", - route_name="v1_tax_report", - renderer="json", - permission="Tax Report", + request_method="GET", route_name="v1_tax_report", renderer="json", permission="Tax Report", ) def get_tax_view(request): start_date = get_start_date(request.GET.get("s", None)) @@ -130,11 +124,6 @@ def get_tax(start_date, finish_date, dbsession): .all() ) return [ - { - "name": "{0} - {1:.2%}".format(i[0], i[1]), - "taxRate": i[1], - "saleAmount": i[2], - "amount": i[3], - } + {"name": "{0} - {1:.2%}".format(i[0], i[1]), "taxRate": i[1], "saleAmount": i[2], "amount": i[3],} for i in amounts ] diff --git a/barker/views/reprint.py b/barker/routers/reprint.py similarity index 61% rename from barker/views/reprint.py rename to barker/routers/reprint.py index 9a59724..a46aabf 100644 --- a/barker/views/reprint.py +++ b/barker/routers/reprint.py @@ -6,9 +6,11 @@ from pyramid.view import view_config from barker.models import Reprint -@view_config(request_method='POST', route_name='v1_reprint', renderer='json', permission='Print Bill', trans=True) +@view_config( + request_method="POST", route_name="v1_reprint", renderer="json", permission="Print Bill", trans=True, +) def save(request): - id_ = uuid.UUID(request.matchdict['id']) + id_ = uuid.UUID(request.matchdict["id"]) item = Reprint(id_, uuid.UUID(request.authenticated_userid)) request.dbsession.add(item) transaction.commit() diff --git a/barker/views/role.py b/barker/routers/role.py similarity index 63% rename from barker/views/role.py rename to barker/routers/role.py index 62c6b24..dd4824a 100644 --- a/barker/views/role.py +++ b/barker/routers/role.py @@ -8,11 +8,7 @@ from barker.models import Permission, Role @view_config( - request_method="POST", - route_name="v1_roles_new", - renderer="json", - permission="Users", - trans=True, + request_method="POST", route_name="v1_roles_new", renderer="json", permission="Users", trans=True, ) def save(request): item = Role(request.json_body["name"]) @@ -23,11 +19,7 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_roles_id", - renderer="json", - permission="Users", - trans=True, + request_method="PUT", route_name="v1_roles_id", renderer="json", permission="Users", trans=True, ) def update(request): id_ = request.matchdict["id"] @@ -44,20 +36,14 @@ def add_permissions(role, permissions, dbsession): rp = [p for p in role.permissions if p.id == id_] rp = None if len(rp) == 0 else rp[0] if permission["enabled"] and rp is None: - permission_object = ( - dbsession.query(Permission).filter(Permission.id == id_).one() - ) + permission_object = dbsession.query(Permission).filter(Permission.id == id_).one() role.permissions.append(permission_object) elif not permission["enabled"] and rp: role.permissions.remove(rp) @view_config( - request_method="DELETE", - route_name="v1_roles_id", - renderer="json", - permission="Users", - trans=True, + request_method="DELETE", route_name="v1_roles_id", renderer="json", permission="Users", trans=True, ) def delete(request): id_ = request.matchdict["id"] @@ -72,10 +58,7 @@ def delete(request): @view_config( - request_method="GET", - route_name="v1_roles_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_roles_id", renderer="json", permission="Authenticated", ) def show_id(request): id_ = uuid.UUID(request.matchdict["id"]) @@ -83,30 +66,19 @@ def show_id(request): @view_config( - request_method="GET", - route_name="v1_roles_new", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_roles_new", renderer="json", permission="Authenticated", ) def show_blank(request): return role_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_roles_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_roles_list", renderer="json", permission="Authenticated", ) def show_list(request): list_ = request.dbsession.query(Role).order_by(Role.name).all() return [ - { - "id": item.id, - "name": item.name, - "permissions": sorted(p.name for p in item.permissions), - } - for item in list_ + {"id": item.id, "name": item.name, "permissions": sorted(p.name for p in item.permissions),} for item in list_ ] @@ -115,9 +87,7 @@ def role_info(item, dbsession): if item is None: return { "name": "", - "permissions": [ - {"id": p.id, "name": p.name, "enabled": False} for p in permissions - ], + "permissions": [{"id": p.id, "name": p.name, "enabled": False} for p in permissions], } if type(item) is uuid.UUID: item = dbsession.query(Role).filter(Role.id == item).first() @@ -125,11 +95,6 @@ def role_info(item, dbsession): "id": item.id, "name": item.name, "permissions": [ - { - "id": p.id, - "name": p.name, - "enabled": True if p in item.permissions else False, - } - for p in permissions + {"id": p.id, "name": p.name, "enabled": True if p in item.permissions else False,} for p in permissions ], } diff --git a/barker/routers/sale_category.py b/barker/routers/sale_category.py new file mode 100644 index 0000000..4eedf41 --- /dev/null +++ b/barker/routers/sale_category.py @@ -0,0 +1,119 @@ +import uuid +from typing import Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ..schemas.auth import UserToken +import barker.schemas.master as schemas +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal +from ..models.master import SaleCategory + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/", response_model=schemas.SaleCategory) +def save( + data: schemas.SaleCategoryIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item = SaleCategory(name=data.name, tax_id=data.tax.id_) + db.add(item) + db.commit() + return sale_category_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.SaleCategory) +def update( + id_: uuid.UUID, + data: schemas.SaleCategoryIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: SaleCategory = db.query(SaleCategory).filter(SaleCategory.id == id_).first() + item.name = data.name + item.tax_id = data.tax.id_ + db.commit() + return sale_category_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: SaleCategory = db.query(SaleCategory).filter(SaleCategory.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Sale Category not found", + ) + else: + raise HTTPException( + status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Sale Category deletion not implemented", + ) + except Exception: + db.rollback() + raise + + +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + return sale_category_info(None) + + +@router.get("/list") +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [sale_category_info(item) for item in db.query(SaleCategory).order_by(SaleCategory.name).all()] + + +@router.get("/for-discount") +def for_discount(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [{"id": item.id, "name": item.name, "discount": 0} for item in db.query(SaleCategory).order_by(SaleCategory.name).all()] + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + item: SaleCategory = db.query(SaleCategory).filter(SaleCategory.id == id_).first() + return sale_category_info(item) + + +def sale_category_info(item: Optional[SaleCategory]): + if item is None: + return {"name": "", "tax": {}} + return { + "id": item.id, + "name": item.name, + "tax": {"id": item.tax_id, "name": item.tax.name, "rate": item.tax.rate}, + } diff --git a/barker/views/section.py b/barker/routers/section.py similarity index 53% rename from barker/views/section.py rename to barker/routers/section.py index 7f1b1b0..cd94493 100644 --- a/barker/views/section.py +++ b/barker/routers/section.py @@ -7,11 +7,7 @@ from barker.models.validation_exception import ValidationError @view_config( - request_method="POST", - route_name="v1_sections_new", - renderer="json", - permission="Sections", - trans=True, + request_method="POST", route_name="v1_sections_new", renderer="json", permission="Sections", trans=True, ) def save(request): json = request.json_body @@ -25,19 +21,11 @@ def save(request): @view_config( - request_method="PUT", - route_name="v1_sections_id", - renderer="json", - permission="Sections", - trans=True, + request_method="PUT", route_name="v1_sections_id", renderer="json", permission="Sections", trans=True, ) def update(request): json = request.json_body - item = ( - request.dbsession.query(Section) - .filter(Section.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Section).filter(Section.id == uuid.UUID(request.matchdict["id"])).first() item.name = json.get("name", "").strip() if item.name == "": raise ValidationError("Name cannot be blank") @@ -46,57 +34,37 @@ def update(request): @view_config( - request_method="DELETE", - route_name="v1_sections_id", - renderer="json", - permission="Sections", - trans=True, + request_method="DELETE", route_name="v1_sections_id", renderer="json", permission="Sections", trans=True, ) def delete(request): - item = ( - request.dbsession.query(Section) - .filter(Section.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Section).filter(Section.id == uuid.UUID(request.matchdict["id"])).first() if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) + raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name)) request.dbsession.delete(item) transaction.commit() return section_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_sections_new", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_sections_new", renderer="json", permission="Authenticated", ) def show_blank(request): return section_info(None, request.dbsession) @view_config( - request_method="GET", - route_name="v1_sections_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_sections_id", renderer="json", permission="Authenticated", ) def show_id(request): return section_info(uuid.UUID(request.matchdict["id"]), request.dbsession) @view_config( - request_method="GET", - route_name="v1_sections_list", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_sections_list", renderer="json", permission="Authenticated", ) def show_list(request): return [ - section_info(item, request.dbsession) - for item in request.dbsession.query(Section).order_by(Section.name).all() + section_info(item, request.dbsession) for item in request.dbsession.query(Section).order_by(Section.name).all() ] diff --git a/barker/views/section_printer.py b/barker/routers/section_printer.py similarity index 79% rename from barker/views/section_printer.py rename to barker/routers/section_printer.py index 838b36b..43eb053 100644 --- a/barker/views/section_printer.py +++ b/barker/routers/section_printer.py @@ -24,17 +24,12 @@ def save(request): for mcs in json["menuCategories"]: menu_category = mcs.get("menuCategory", None) menu_category_id = ( - uuid.UUID(menu_category["id"]) - if menu_category is not None and menu_category["id"] != "" - else None + uuid.UUID(menu_category["id"]) if menu_category is not None and menu_category["id"] != "" else None ) printer = mcs.get("printer", None) printer_id = ( uuid.UUID(printer["id"]) - if printer is not None - and "id" in printer - and printer["id"] is not None - and printer["id"] != "" + if printer is not None and "id" in printer and printer["id"] is not None and printer["id"] != "" else None ) if menu_category_id is None and printer_id is None: @@ -57,17 +52,13 @@ def save(request): copies=copies, ) .on_conflict_do_update( - index_elements=["menu_category_id", "section_id"], - set_=dict(printer_id=printer_id, copies=copies), + index_elements=["menu_category_id", "section_id"], set_=dict(printer_id=printer_id, copies=copies), ) ) request.dbsession.execute(stmt) current.append(menu_category_id) SectionPrinter.__table__.delete( - and_( - SectionPrinter.section_id == section_id, - ~SectionPrinter.menu_category_id.in_(current), - ) + and_(SectionPrinter.section_id == section_id, ~SectionPrinter.menu_category_id.in_(current),) ) mark_changed(request.dbsession) transaction.commit() @@ -91,16 +82,10 @@ def delete(request): @view_config( - request_method="GET", - route_name="v1_section_printers", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_section_printers", renderer="json", permission="Authenticated", ) @view_config( - request_method="GET", - route_name="v1_section_printers_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_section_printers_id", renderer="json", permission="Authenticated", ) def show_id(request): section_id = request.matchdict.get("section_id", None) @@ -123,10 +108,7 @@ def show_details(request): menu_category_id = uuid.UUID(menu_category_id) item = ( request.dbsession.query(SectionPrinter) - .filter( - SectionPrinter.section_id == section_id, - SectionPrinter.menu_category_id == menu_category_id, - ) + .filter(SectionPrinter.section_id == section_id, SectionPrinter.menu_category_id == menu_category_id,) .first() ) return section_printer_info(item, request.dbsession) @@ -143,17 +125,12 @@ def report(section_id, dbsession): for item in [(None,)] + menu_categories: mc = ( dbsession.query(SectionPrinter) - .filter( - SectionPrinter.section_id == section_id, - SectionPrinter.menu_category_id == item[0], - ) + .filter(SectionPrinter.section_id == section_id, SectionPrinter.menu_category_id == item[0],) .first() ) list_.append( { - "menuCategory": {"id": "", "name": "Default"} - if item[0] is None - else {"id": item[0], "name": item[1]}, + "menuCategory": {"id": "", "name": "Default"} if item[0] is None else {"id": item[0], "name": item[1]}, "printer": {} if mc is None else {"id": mc.printer_id}, "copies": 0 if mc is None else mc.copies, } diff --git a/barker/routers/setting.py b/barker/routers/setting.py new file mode 100644 index 0000000..5f0ef06 --- /dev/null +++ b/barker/routers/setting.py @@ -0,0 +1,12 @@ +from pyramid.view import view_config + +from barker.models import DbSetting + + +@view_config( + request_method="GET", route_name="v1_settings_id", renderer="json", permission="Authenticated", +) +def show_id(request): + name = request.matchdict["id"] + item = request.dbsession.query(DbSetting).filter(DbSetting.name == name).first() + return {"SettingID": item.id, "Name": item.name, "Details": item.data} diff --git a/barker/routers/tax.py b/barker/routers/tax.py new file mode 100644 index 0000000..0ff24db --- /dev/null +++ b/barker/routers/tax.py @@ -0,0 +1,128 @@ +import uuid +from typing import Optional + +from fastapi import APIRouter, HTTPException, status, Depends, Security +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from ..schemas.auth import UserToken +import barker.schemas.master as schemas +from ..core.security import get_current_active_user as get_user +from ..db.session import SessionLocal +from ..models.master import Tax + +router = APIRouter() + + +# Dependency +def get_db(): + try: + db = SessionLocal() + yield db + finally: + db.close() + + +@router.post("/", response_model=schemas.Tax) +def save( + data: schemas.TaxIn, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item = Tax(name=data.name, rate=data.rate) + db.add(item) + db.commit() + return tax_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.put("/{id_}", response_model=schemas.Tax) +def update( + id_: uuid.UUID, + data: schemas.TaxIn, + db: Session = Depends(get_db), + user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: Tax = db.query(Tax).filter(Tax.id == id_).first() + if item.is_fixture: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", + ) + item.name = data.name + item.rate = data.rate + db.commit() + return tax_info(item) + except SQLAlchemyError as e: + db.rollback() + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), + ) + except Exception: + db.rollback() + raise + + +@router.delete("/{id_}") +def delete( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + try: + item: Tax = db.query(Tax).filter(Tax.id == id_).first() + if item is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Tax not found", + ) + elif item.is_fixture: + raise HTTPException( + status_code=status.HTTP_423_LOCKED, detail=f"{item.name} is a fixture and cannot be edited or deleted.", + ) + else: + db.delete(item) + db.commit() + return tax_info(None) + except Exception: + db.rollback() + raise + + +@router.get("/") +def show_blank( + db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + return tax_info(None) + + +@router.get("/list") +def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)): + return [ + {"id": item.id, "name": item.name, "rate": item.rate, "isFixture": item.is_fixture} + for item in db.query(Tax).order_by(Tax.name).all() + ] + + +@router.get("/{id_}") +def show_id( + id_: uuid.UUID, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["products"]), +): + item: Tax = db.query(Tax).filter(Tax.id == id_).first() + return tax_info(item) + + +def tax_info(item: Optional[Tax]): + if item is None: + tax = {"name": "", "rate": 0, "isFixture": False} + else: + tax = { + "id": item.id, + "name": item.name, + "rate": item.rate * 100, + "isFixture": item.is_fixture, + } + return tax diff --git a/barker/views/voucher/__init__.py b/barker/routers/voucher/__init__.py similarity index 87% rename from barker/views/voucher/__init__.py rename to barker/routers/voucher/__init__.py index 34680e8..90cb4b6 100644 --- a/barker/views/voucher/__init__.py +++ b/barker/routers/voucher/__init__.py @@ -2,9 +2,14 @@ import uuid from sqlalchemy import func -from barker.exceptions import ValidationFailure -from barker.models import VoucherType, Settlement, SettleOption, Voucher, Overview, GuestBook -from barker.models.validation_exception import ValidationError +from barker.models import ( + VoucherType, + Settlement, + SettleOption, + Voucher, + Overview, + GuestBook, +) def get_tax(tax, voucher_type): @@ -59,19 +64,13 @@ def check_permissions(item, voucher_type, permissions): raise ValidationFailure("This Bill is already printed\nCannot add a Kot to it.") if item.voucher_type == VoucherType.VOID: - raise ValidationFailure( - "This Bill is already void.\nReason: {0}".format(item.reason) - ) + raise ValidationFailure("This Bill is already void.\nReason: {0}".format(item.reason)) def get_guest_book(guest_book_id, dbsession): if guest_book_id is None: return guest_book_id - return ( - dbsession.query(GuestBook) - .filter(GuestBook.id == uuid.UUID(guest_book_id)) - .first() - ) + return dbsession.query(GuestBook).filter(GuestBook.id == uuid.UUID(guest_book_id)).first() def do_update_settlements(voucher, dbsession): diff --git a/barker/views/voucher/change.py b/barker/routers/voucher/change.py similarity index 100% rename from barker/views/voucher/change.py rename to barker/routers/voucher/change.py diff --git a/barker/views/voucher/merge_move.py b/barker/routers/voucher/merge_move.py similarity index 90% rename from barker/views/voucher/merge_move.py rename to barker/routers/voucher/merge_move.py index 9b92734..dad78f8 100644 --- a/barker/views/voucher/merge_move.py +++ b/barker/routers/voucher/merge_move.py @@ -22,9 +22,7 @@ def merge_kot(request): kot_id = uuid.UUID(json["kot"]["id"]) new_voucher_id = uuid.UUID(json["newVoucher"]["id"]) - request.dbsession.query(Kot).filter(Kot.id == kot_id).update( - {Kot.voucher_id: new_voucher_id} - ) + request.dbsession.query(Kot).filter(Kot.id == kot_id).update({Kot.voucher_id: new_voucher_id}) transaction.commit() return True @@ -45,9 +43,7 @@ def move_kot(request): kot = request.dbsession.query(Kot).filter(Kot.id == kot_id).first() bill_id = get_bill_id(kot.voucher.voucher_type, request.dbsession) - kot_id = request.dbsession.query( - func.coalesce(func.max(Voucher.kot_id), 0) + 1 - ).scalar() + kot_id = request.dbsession.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar() item = Voucher( now, @@ -57,7 +53,7 @@ def move_kot(request): table_id, kot.voucher.customer_id, kot.voucher.voucher_type, - uuid.UUID(request.authenticated_userid) + uuid.UUID(request.authenticated_userid), ) request.dbsession.add(item) item.kots.append(kot) @@ -79,13 +75,9 @@ def move_table(request): id_ = uuid.UUID(request.json_body["voucher"]["id"]) table_id = uuid.UUID(request.json_body["table"]["id"]) - request.dbsession.query(Overview).filter(Overview.voucher_id == id_).update( - {Overview.food_table_id: table_id} - ) + request.dbsession.query(Overview).filter(Overview.voucher_id == id_).update({Overview.food_table_id: table_id}) - request.dbsession.query(Voucher).filter(Voucher.id == id_).update( - {Voucher.food_table_id: table_id} - ) + request.dbsession.query(Voucher).filter(Voucher.id == id_).update({Voucher.food_table_id: table_id}) transaction.commit() return True @@ -106,9 +98,7 @@ def merge_table(request): # table_id = uuid.UUID(json["table"]["id"]) new_voucher_id = uuid.UUID(json["newVoucher"]["id"]) - request.dbsession.query(Kot).filter(Kot.voucher_id == id_).update( - {Kot.voucher_id: new_voucher_id} - ) + request.dbsession.query(Kot).filter(Kot.voucher_id == id_).update({Kot.voucher_id: new_voucher_id}) request.dbsession.query(Voucher).filter(Voucher.id == id_).delete() transaction.commit() return True diff --git a/barker/views/voucher/receive_payment.py b/barker/routers/voucher/receive_payment.py similarity index 89% rename from barker/views/voucher/receive_payment.py rename to barker/routers/voucher/receive_payment.py index f13ef57..46988e8 100644 --- a/barker/views/voucher/receive_payment.py +++ b/barker/routers/voucher/receive_payment.py @@ -22,8 +22,7 @@ def receive_payment(request): amounts = [ j for j in json["amounts"] - if j["amount"] != 0 - and j["id"] not in [SettleOption.AMOUNT(), SettleOption.ROUND_OFF()] + if j["amount"] != 0 and j["id"] not in [SettleOption.AMOUNT(), SettleOption.ROUND_OFF()] ] for item in amounts: item["amount"] = round(Decimal(item["amount"]), 0) @@ -59,8 +58,6 @@ def receive_payment(request): request.dbsession.delete(i) if update_table: - request.dbsession.query(Overview).filter( - Overview.voucher_id == item.id - ).delete() + request.dbsession.query(Overview).filter(Overview.voucher_id == item.id).delete() transaction.commit() return True diff --git a/barker/views/voucher/save.py b/barker/routers/voucher/save.py similarity index 86% rename from barker/views/voucher/save.py rename to barker/routers/voucher/save.py index 2175c7a..642dee3 100644 --- a/barker/views/voucher/save.py +++ b/barker/routers/voucher/save.py @@ -26,9 +26,7 @@ from barker.views.voucher import ( ) -@view_config( - request_method="POST", route_name="v1_vouchers_new", renderer="json", trans=True -) +@view_config(request_method="POST", route_name="v1_vouchers_new", renderer="json", trans=True) def save(request): json = request.json_body now = datetime.datetime.now() @@ -39,9 +37,7 @@ def save(request): check_permissions(None, voucher_type, request.effective_principals) bill_id = get_bill_id(voucher_type, request.dbsession) - kot_id = request.dbsession.query( - func.coalesce(func.max(Voucher.kot_id), 0) + 1 - ).scalar() + kot_id = request.dbsession.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar() item = Voucher( now, @@ -60,11 +56,7 @@ def save(request): item.kots.append(kot) request.dbsession.add(kot) for index, i in enumerate(k["inventories"]): - product = ( - request.dbsession.query(Product) - .filter(Product.id == uuid.UUID(i["product"]["id"])) - .first() - ) + product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(i["product"]["id"])).first() tax_rate = get_tax(product.sale_category.tax.rate, voucher_type) inv = Inventory( kot.id, diff --git a/barker/views/voucher/show.py b/barker/routers/voucher/show.py similarity index 79% rename from barker/views/voucher/show.py rename to barker/routers/voucher/show.py index 5c33da2..b1e4f2b 100644 --- a/barker/views/voucher/show.py +++ b/barker/routers/voucher/show.py @@ -8,10 +8,7 @@ from barker.models import Voucher, Overview, FoodTable, GuestBook, VoucherType @view_config( - request_method="GET", - route_name="v1_vouchers_id", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_vouchers_id", renderer="json", permission="Authenticated", ) def show_id(request): id_ = uuid.UUID(request.matchdict["id"]) @@ -20,30 +17,17 @@ def show_id(request): @view_config( - request_method="GET", - route_name="v1_vouchers_new", - request_param="b", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_vouchers_new", request_param="b", renderer="json", permission="Authenticated", ) def show(request): bill_id = request.GET["b"] item = request.dbsession.query(Voucher) if re.compile("^\d{2,}-\d{4}$").match(bill_id): - item = item.filter( - Voucher.bill_id == int(bill_id.replace("-", "")), - Voucher.voucher_type.in_([1, 3]), - ) + item = item.filter(Voucher.bill_id == int(bill_id.replace("-", "")), Voucher.voucher_type.in_([1, 3]),) elif re.compile("^NC-\d+$").match(bill_id): - item = item.filter( - Voucher.bill_id == int(bill_id.replace("NC-", "")), - Voucher.voucher_type == 2, - ) + item = item.filter(Voucher.bill_id == int(bill_id.replace("NC-", "")), Voucher.voucher_type == 2,) elif re.compile("^ST-\d+$").match(bill_id): - item = item.filter( - Voucher.bill_id == int(bill_id.replace("ST-", "")), - Voucher.voucher_type == 4, - ) + item = item.filter(Voucher.bill_id == int(bill_id.replace("ST-", "")), Voucher.voucher_type == 4,) item = item.first() if item is None: return {} @@ -51,11 +35,7 @@ def show(request): @view_config( - request_method="GET", - route_name="v1_vouchers_new", - request_param="t", - renderer="json", - permission="Authenticated", + request_method="GET", route_name="v1_vouchers_new", request_param="t", renderer="json", permission="Authenticated", ) def show_for_table(request): table_id = uuid.UUID(request.GET["t"]) @@ -64,10 +44,7 @@ def show_for_table(request): if voucher_id is not None: item = ( request.dbsession.query(Overview) - .filter( - Overview.voucher_id == uuid.UUID(voucher_id), - Overview.food_table_id == table_id, - ) + .filter(Overview.voucher_id == uuid.UUID(voucher_id), Overview.food_table_id == table_id,) .first() ) if item is None: @@ -119,10 +96,7 @@ def voucher_info(item): "name": i.product.menu_category.name, "discountLimit": i.product.menu_category.discount_limit, }, - "saleCategory": { - "id": i.product.sale_category_id, - "name": i.product.sale_category.name, - }, + "saleCategory": {"id": i.product.sale_category_id, "name": i.product.sale_category.name,}, }, "quantity": i.quantity, "price": i.price, @@ -157,7 +131,5 @@ def voucher_blank(table, guest): "table": {"id": table.id, "name": table.name}, "voucherType": VoucherType.KOT.name, "customer": {"id": guest.customer_id, "name": guest.customer.name} if guest is not None else {}, - "kots": [] + "kots": [], } - - diff --git a/barker/views/voucher/split.py b/barker/routers/voucher/split.py similarity index 88% rename from barker/views/voucher/split.py rename to barker/routers/voucher/split.py index fc1ca70..6adf7e7 100644 --- a/barker/views/voucher/split.py +++ b/barker/routers/voucher/split.py @@ -30,9 +30,7 @@ def split_voucher(request): item.reason = "Bill Split" do_void_settlements(item, request.dbsession) if update_table: - request.dbsession.query(Overview).filter( - Overview.voucher_id == item.id - ).delete() + request.dbsession.query(Overview).filter(Overview.voucher_id == item.id).delete() inventories = [uuid.UUID(i) for i in json["inventories"]] @@ -69,16 +67,7 @@ def split_voucher(request): def save( - inventories, - now, - voucher_type, - pax, - table_id, - customer_id, - update_table, - user_id, - permissions, - dbsession, + inventories, now, voucher_type, pax, table_id, customer_id, update_table, user_id, permissions, dbsession, ): product_quantities = {} skip_products = set() @@ -96,17 +85,13 @@ def save( bill_id = get_bill_id(voucher_type, dbsession) kot_id = dbsession.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar() - item = Voucher( - now, pax, bill_id, kot_id, table_id, customer_id, voucher_type, user_id - ) + item = Voucher(now, pax, bill_id, kot_id, table_id, customer_id, voucher_type, user_id) dbsession.add(item) code = dbsession.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar() kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id) item.kots.append(kot) dbsession.add(kot) - for index, old_inventory in enumerate( - [i for i in inventories if i.product_id not in skip_products] - ): + for index, old_inventory in enumerate([i for i in inventories if i.product_id not in skip_products]): inv = Inventory( kot.id, old_inventory.product_id, diff --git a/barker/views/voucher/update.py b/barker/routers/voucher/update.py similarity index 87% rename from barker/views/voucher/update.py rename to barker/routers/voucher/update.py index 9c22e9e..f0e48d8 100644 --- a/barker/views/voucher/update.py +++ b/barker/routers/voucher/update.py @@ -24,20 +24,14 @@ from barker.views.voucher import ( ) -@view_config( - request_method="PUT", route_name="v1_vouchers_id", renderer="json", trans=True -) +@view_config(request_method="PUT", route_name="v1_vouchers_id", renderer="json", trans=True) def update(request): json = request.json_body now = datetime.datetime.now() update_table = request.GET["u"] == "true" voucher_type = VoucherType[request.GET["p"]] guest_book = get_guest_book(request.GET.get("g", None), request.dbsession) - item = ( - request.dbsession.query(Voucher) - .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) - .first() - ) + item = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(request.matchdict["id"])).first() check_permissions(item, voucher_type, request.effective_principals) @@ -67,11 +61,7 @@ def update(request): item.kots.append(kot) request.dbsession.add(kot) for index, i in enumerate(k["inventories"]): - product = ( - request.dbsession.query(Product) - .filter(Product.id == uuid.UUID(i["product"]["id"])) - .first() - ) + product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(i["product"]["id"])).first() tax_rate = get_tax(product.sale_category.tax.rate, voucher_type) inv = Inventory( kot.id, diff --git a/barker/views/voucher/void.py b/barker/routers/voucher/void.py similarity index 93% rename from barker/views/voucher/void.py rename to barker/routers/voucher/void.py index 1716c98..ab31991 100644 --- a/barker/views/voucher/void.py +++ b/barker/routers/voucher/void.py @@ -28,9 +28,7 @@ def void_voucher(request): do_void_settlements(item, request.dbsession) if update_table: - request.dbsession.query(Overview).filter( - Overview.voucher_id == item.id - ).delete() + request.dbsession.query(Overview).filter(Overview.voucher_id == item.id).delete() transaction.commit() return True diff --git a/barker/routes.py b/barker/routes.py index 0d48ab2..f80179f 100644 --- a/barker/routes.py +++ b/barker/routes.py @@ -10,24 +10,15 @@ def includeme(config): config.add_route("v1_devices_list", "/v1/devices") config.add_route("devices_new", "/devices/new") config.add_view( - "barker.views.home", - route_name="devices_new", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="devices_new", request_method="GET", permission="Tables", ) config.add_route("devices_id", "/devices/{id}") config.add_view( - "barker.views.home", - route_name="devices_id", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="devices_id", request_method="GET", permission="Tables", ) config.add_route("devices_list", "/devices") config.add_view( - "barker.views.home", - route_name="devices_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="devices_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_guest_book_new", "/v1/guest-book/new") @@ -35,24 +26,15 @@ def includeme(config): config.add_route("v1_guest_book_list", "/v1/guest-book") config.add_route("guest_book_new", "/guest-book/new") config.add_view( - "barker.views.home", - route_name="guest_book_new", - request_method="GET", - permission="Guest Book", + "barker.views.home", route_name="guest_book_new", request_method="GET", permission="Guest Book", ) config.add_route("guest_book_id", "/guest-book/{id}") config.add_view( - "barker.views.home", - route_name="guest_book_id", - request_method="GET", - permission="Guest Book", + "barker.views.home", route_name="guest_book_id", request_method="GET", permission="Guest Book", ) config.add_route("guest_book_list", "/guest-book") config.add_view( - "barker.views.home", - route_name="guest_book_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="guest_book_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_menu_categories_new", "/v1/menu-categories/new") @@ -60,24 +42,15 @@ def includeme(config): config.add_route("v1_menu_categories_list", "/v1/menu-categories") config.add_route("menu_categories_new", "/menu-categories/new") config.add_view( - "barker.views.home", - route_name="menu_categories_new", - request_method="GET", - permission="Products", + "barker.views.home", route_name="menu_categories_new", request_method="GET", permission="Products", ) config.add_route("menu_categories_id", "/menu-categories/{id}") config.add_view( - "barker.views.home", - route_name="menu_categories_id", - request_method="GET", - permission="Products", + "barker.views.home", route_name="menu_categories_id", request_method="GET", permission="Products", ) config.add_route("menu_categories_list", "/menu-categories") config.add_view( - "barker.views.home", - route_name="menu_categories_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="menu_categories_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_modifier_categories_new", "/v1/modifier-categories/new") @@ -85,24 +58,15 @@ def includeme(config): config.add_route("v1_modifier_categories_list", "/v1/modifier-categories") config.add_route("modifier_categories_new", "/modifier-categories/new") config.add_view( - "barker.views.home", - route_name="modifier_categories_new", - request_method="GET", - permission="Products", + "barker.views.home", route_name="modifier_categories_new", request_method="GET", permission="Products", ) config.add_route("modifier_categories_id", "/modifier-categories/{id}") config.add_view( - "barker.views.home", - route_name="modifier_categories_id", - request_method="GET", - permission="Products", + "barker.views.home", route_name="modifier_categories_id", request_method="GET", permission="Products", ) config.add_route("modifier_categories_list", "/modifier-categories") config.add_view( - "barker.views.home", - route_name="modifier_categories_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="modifier_categories_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_modifiers_new", "/v1/modifiers/new") @@ -110,24 +74,15 @@ def includeme(config): config.add_route("v1_modifiers_list", "/v1/modifiers") config.add_route("modifiers_new", "/modifiers/new") config.add_view( - "barker.views.home", - route_name="modifiers_new", - request_method="GET", - permission="Products", + "barker.views.home", route_name="modifiers_new", request_method="GET", permission="Products", ) config.add_route("modifiers_id", "/modifiers/{id}") config.add_view( - "barker.views.home", - route_name="modifiers_id", - request_method="GET", - permission="Products", + "barker.views.home", route_name="modifiers_id", request_method="GET", permission="Products", ) config.add_route("modifiers_list", "/modifiers") config.add_view( - "barker.views.home", - route_name="modifiers_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="modifiers_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_printers_new", "/v1/printers/new") @@ -135,24 +90,15 @@ def includeme(config): config.add_route("v1_printers_list", "/v1/printers") config.add_route("printers_new", "/printers/new") config.add_view( - "barker.views.home", - route_name="printers_new", - request_method="GET", - permission="Printers", + "barker.views.home", route_name="printers_new", request_method="GET", permission="Printers", ) config.add_route("printers_id", "/printers/{id}") config.add_view( - "barker.views.home", - route_name="printers_id", - request_method="GET", - permission="Printers", + "barker.views.home", route_name="printers_id", request_method="GET", permission="Printers", ) config.add_route("printers_list", "/printers") config.add_view( - "barker.views.home", - route_name="printers_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="printers_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_products_new", "/v1/products/new") @@ -160,24 +106,15 @@ def includeme(config): config.add_route("v1_products_list", "/v1/products") config.add_route("products_new", "/products/new") config.add_view( - "barker.views.home", - route_name="products_new", - request_method="GET", - permission="Products", + "barker.views.home", route_name="products_new", request_method="GET", permission="Products", ) config.add_route("products_id", "/products/{id}") config.add_view( - "barker.views.home", - route_name="products_id", - request_method="GET", - permission="Products", + "barker.views.home", route_name="products_id", request_method="GET", permission="Products", ) config.add_route("products_list", "/products") config.add_view( - "barker.views.home", - route_name="products_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="products_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_roles_new", "/v1/roles/new") @@ -185,24 +122,15 @@ def includeme(config): config.add_route("v1_roles_list", "/v1/roles") config.add_route("roles_new", "/roles/new") config.add_view( - "barker.views.home", - route_name="roles_new", - request_method="GET", - permission="Users", + "barker.views.home", route_name="roles_new", request_method="GET", permission="Users", ) config.add_route("roles_id", "/roles/{id}") config.add_view( - "barker.views.home", - route_name="roles_id", - request_method="GET", - permission="Users", + "barker.views.home", route_name="roles_id", request_method="GET", permission="Users", ) config.add_route("roles_list", "/roles") config.add_view( - "barker.views.home", - route_name="roles_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="roles_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_sale_categories_new", "/v1/sale-categories/new") @@ -210,41 +138,26 @@ def includeme(config): config.add_route("v1_sale_categories_list", "/v1/sale-categories") config.add_route("sale_categories_new", "/sale-categories/new") config.add_view( - "barker.views.home", - route_name="sale_categories_new", - request_method="GET", - permission="Products", + "barker.views.home", route_name="sale_categories_new", request_method="GET", permission="Products", ) config.add_route("sale_categories_id", "/sale-categories/{id}") config.add_view( - "barker.views.home", - route_name="sale_categories_id", - request_method="GET", - permission="Products", + "barker.views.home", route_name="sale_categories_id", request_method="GET", permission="Products", ) config.add_route("sale_categories_list", "/sale-categories") config.add_view( - "barker.views.home", - route_name="sale_categories_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="sale_categories_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_section_printers", "/v1/section-printers") config.add_route("v1_section_printers_id", "/v1/section-printers/{section_id}") config.add_route("section_printers_id", "/section-printers/{section_id}") config.add_view( - "barker.views.home", - route_name="section_printers_id", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="section_printers_id", request_method="GET", permission="Tables", ) config.add_route("section_printers", "/section-printers") config.add_view( - "barker.views.home", - route_name="section_printers", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="section_printers", request_method="GET", permission="Tables", ) config.add_route("v1_sections_new", "/v1/sections/new") @@ -252,24 +165,15 @@ def includeme(config): config.add_route("v1_sections_list", "/v1/sections") config.add_route("sections_new", "/sections/new") config.add_view( - "barker.views.home", - route_name="sections_new", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="sections_new", request_method="GET", permission="Tables", ) config.add_route("sections_id", "/sections/{id}") config.add_view( - "barker.views.home", - route_name="sections_id", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="sections_id", request_method="GET", permission="Tables", ) config.add_route("sections_list", "/sections") config.add_view( - "barker.views.home", - route_name="sections_list", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="sections_list", request_method="GET", permission="Tables", ) config.add_route("v1_tables_new", "/v1/tables/new") @@ -277,24 +181,15 @@ def includeme(config): config.add_route("v1_tables_list", "/v1/tables") config.add_route("tables_new", "/tables/new") config.add_view( - "barker.views.home", - route_name="tables_new", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="tables_new", request_method="GET", permission="Tables", ) config.add_route("tables_id", "/tables/{id}") config.add_view( - "barker.views.home", - route_name="tables_id", - request_method="GET", - permission="Tables", + "barker.views.home", route_name="tables_id", request_method="GET", permission="Tables", ) config.add_route("tables_list", "/tables") config.add_view( - "barker.views.home", - route_name="tables_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="tables_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_taxes_new", "/v1/taxes/new") @@ -302,24 +197,15 @@ def includeme(config): config.add_route("v1_taxes_list", "/v1/taxes") config.add_route("taxes_new", "/taxes/new") config.add_view( - "barker.views.home", - route_name="taxes_new", - request_method="GET", - permission="Taxes", + "barker.views.home", route_name="taxes_new", request_method="GET", permission="Taxes", ) config.add_route("taxes_id", "/taxes/{id}") config.add_view( - "barker.views.home", - route_name="taxes_id", - request_method="GET", - permission="Taxes", + "barker.views.home", route_name="taxes_id", request_method="GET", permission="Taxes", ) config.add_route("taxes_list", "/taxes") config.add_view( - "barker.views.home", - route_name="taxes_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="taxes_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_users_new", "/v1/users/new") @@ -327,24 +213,15 @@ def includeme(config): config.add_route("v1_users_list", "/v1/users") config.add_route("users_new", "/users/new") config.add_view( - "barker.views.home", - route_name="users_new", - request_method="GET", - permission="Users", + "barker.views.home", route_name="users_new", request_method="GET", permission="Users", ) config.add_route("users_id", "/users/{id}") config.add_view( - "barker.views.home", - route_name="users_id", - request_method="GET", - permission="Users", + "barker.views.home", route_name="users_id", request_method="GET", permission="Users", ) config.add_route("users_list", "/users") config.add_view( - "barker.views.home", - route_name="users_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="users_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_vouchers_new", "/v1/vouchers/new") @@ -352,17 +229,11 @@ def includeme(config): config.add_route("sales", "/sales") config.add_view( - "barker.views.home", - route_name="sales", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="sales", request_method="GET", permission="Authenticated", ) config.add_route("sales_catch", "/sales/*rest") config.add_view( - "barker.views.home", - route_name="sales_catch", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="sales_catch", request_method="GET", permission="Authenticated", ) config.add_route("v1_move_table", "/v1/move-table") @@ -372,70 +243,46 @@ def includeme(config): config.add_route("v1_cashier_report_id", "/v1/cashier-report/{id}") config.add_route("cashier_report_id", "/cashier-report/{id}") config.add_view( - "barker.views.home", - route_name="cashier_report_id", - request_method="GET", - permission="Cashier Checkout", + "barker.views.home", route_name="cashier_report_id", request_method="GET", permission="Cashier Checkout", ) config.add_route("v1_cashier_report", "/v1/cashier-report") config.add_route("cashier_report", "/cashier-report") config.add_view( - "barker.views.home", - route_name="cashier_report", - request_method="GET", - permission="Cashier Checkout", + "barker.views.home", route_name="cashier_report", request_method="GET", permission="Cashier Checkout", ) config.add_route("v1_sale_report", "/v1/sale-report") config.add_route("sale_report", "/sale-report") config.add_view( - "barker.views.home", - route_name="sale_report", - request_method="GET", - permission="Sales Analysis", + "barker.views.home", route_name="sale_report", request_method="GET", permission="Sales Analysis", ) config.add_route("v1_tax_report", "/v1/tax-report") config.add_route("tax_report", "/tax-report") config.add_view( - "barker.views.home", - route_name="tax_report", - request_method="GET", - permission="Tax Analysis", + "barker.views.home", route_name="tax_report", request_method="GET", permission="Tax Analysis", ) config.add_route("v1_product_sale_report", "/v1/product-sale-report") config.add_route("product_sale_report", "/product-sale-report") config.add_view( - "barker.views.home", - route_name="product_sale_report", - request_method="GET", - permission="Sales Detail", + "barker.views.home", route_name="product_sale_report", request_method="GET", permission="Sales Detail", ) config.add_route("v1_bill_settlement_report", "/v1/bill-settlement-report") config.add_route("bill_settlement_report", "/bill-settlement-report") config.add_view( - "barker.views.home", - route_name="bill_settlement_report", - request_method="GET", - permission="Bill Details", + "barker.views.home", route_name="bill_settlement_report", request_method="GET", permission="Bill Details", ) config.add_route("v1_beer_consumption_report", "/v1/beer-consumption-report") config.add_route("beer_consumption_report", "/beer-consumption-report") config.add_view( - "barker.views.home", - route_name="beer_consumption_report", - request_method="GET", - permission="Beer Consumption", + "barker.views.home", route_name="beer_consumption_report", request_method="GET", permission="Beer Consumption", ) config.add_route("v1_discount_report", "/v1/discount-report") config.add_route("discount_report", "/discount-report") config.add_view( - "barker.views.home", - route_name="discount_report", - request_method="GET", - permission="Discount Report", + "barker.views.home", route_name="discount_report", request_method="GET", permission="Discount Report", ) # config.add_route("v1_bills_new", "/v1/bills/new") @@ -446,24 +293,15 @@ def includeme(config): config.add_route("v1_customers_list", "/v1/customers") config.add_route("customers_new", "/customers/new") config.add_view( - "barker.views.home", - route_name="customers_new", - request_method="GET", - permission="Customers", + "barker.views.home", route_name="customers_new", request_method="GET", permission="Customers", ) config.add_route("customers_id", "/customers/{id}") config.add_view( - "barker.views.home", - route_name="customers_id", - request_method="GET", - permission="Customers", + "barker.views.home", route_name="customers_id", request_method="GET", permission="Customers", ) config.add_route("customers_list", "/customers") config.add_view( - "barker.views.home", - route_name="customers_list", - request_method="GET", - permission="Authenticated", + "barker.views.home", route_name="customers_list", request_method="GET", permission="Authenticated", ) config.add_route("v1_reprint", "/v1/reprint/{id}") diff --git a/barker/schemas/__init__.py b/barker/schemas/__init__.py new file mode 100644 index 0000000..2a02c89 --- /dev/null +++ b/barker/schemas/__init__.py @@ -0,0 +1,3 @@ +def to_camel(string: str) -> str: + first, *others = string.split("_") + return "".join([first] + [word.capitalize() for word in others]) diff --git a/barker/schemas/auth.py b/barker/schemas/auth.py new file mode 100644 index 0000000..2fca63f --- /dev/null +++ b/barker/schemas/auth.py @@ -0,0 +1,105 @@ +import uuid +from typing import List, Optional +from datetime import datetime +from pydantic import BaseModel + +from barker.schemas import to_camel + + +class ClientIn(BaseModel): + name: str + enabled: bool + otp: Optional[int] + + +class Client(ClientIn): + id_: uuid.UUID + code: int + creation_date: datetime + + +class LoginHistory(BaseModel): + id_: uuid.UUID + user_id: uuid.UUID + client_id: uuid.UUID + date: datetime + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class PermissionItem(BaseModel): + id_: uuid.UUID + name: str + enabled: bool + + class Config: + fields = {"id_": "id"} + + +class RoleIn(BaseModel): + name: str + permissions: List[PermissionItem] + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + + +class Role(RoleIn): + id_: uuid.UUID + + +class RoleList(BaseModel): + id_: uuid.UUID + name: str + permissions: List[str] + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + + +class RoleItem(BaseModel): + id_: uuid.UUID + name: str + enabled: bool + + class Config: + fields = {"id_": "id"} + + +class UserIn(BaseModel): + name: str + password: str + locked_out: bool + roles: List[RoleItem] + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class User(UserIn): + id_: uuid.UUID + + +class UserList(BaseModel): + id_: uuid.UUID + name: str + roles: List[str] + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + + +class UserToken(BaseModel): + id_: uuid.UUID + name: str + locked_out: bool = None + password: str + permissions: List[str] diff --git a/barker/schemas/master.py b/barker/schemas/master.py new file mode 100644 index 0000000..a105e8c --- /dev/null +++ b/barker/schemas/master.py @@ -0,0 +1,215 @@ +import uuid +from typing import Optional, List +from datetime import date, datetime +from decimal import Decimal + +from pydantic import BaseModel, Field, validator + +from barker.schemas import to_camel + + +class TaxIn(BaseModel): + name: str = Field(..., min_length=1) + rate: Decimal = Field(ge=0, multiple_of=0.0001, default=0, le=1) + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class Tax(TaxIn): + id_: uuid.UUID + is_fixture: bool + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class TaxLink(BaseModel): + id_: uuid.UUID = Field(...) + name: Optional[str] + + class Config: + fields = {"id_": "id"} + + +class SaleCategoryIn(BaseModel): + name: str = Field(..., min_length=1) + tax: TaxLink = Field(...) + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class SaleCategory(SaleCategoryIn): + id_: uuid.UUID + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class SaleCategoryLink(BaseModel): + id_: uuid.UUID = Field(...) + + class Config: + fields = {"id_": "id"} + + +class MenuCategoryIn(BaseModel): + name: str = Field(..., min_length=1) + discount_limit: Decimal = Field(ge=0, multiple_of=0.0001, default=0, le=1) + is_active: bool + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class MenuCategory(MenuCategoryIn): + id_: uuid.UUID + is_fixture: bool + sort_order: int + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class ProductLink(BaseModel): + id_: uuid.UUID = Field(...) + name: Optional[str] + enabled: Optional[bool] + + class Config: + fields = {"id_": "id"} + + +class MenuCategoryLink(BaseModel): + id_: uuid.UUID = Field(...) + products: Optional[List[ProductLink]] + + class Config: + fields = {"id_": "id"} + + +class ProductIn(BaseModel): + name: str = Field(..., min_length=1) + units: str + menu_category: MenuCategoryLink = Field(...) + sale_category: SaleCategoryLink = Field(...) + price: Decimal # = Field(ge=0, multiple_of=0.01, default=0) + has_happy_hour: bool + is_not_available: bool + quantity: Decimal = Field(ge=0, multiple_of=0.01, default=0) + is_active: bool + sort_order: int + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class Product(ProductIn): + id_: uuid.UUID + + +class ModifierCategoryIn(BaseModel): + name: str = Field(..., min_length=1) + minimum: int = Field(ge=0) + maximum: Optional[int] = Field(ge=0) + is_active: bool + menu_categories: Optional[List[MenuCategoryLink]] + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class ModifierCategory(ModifierCategoryIn): + id_: uuid.UUID + sort_order: int + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class AccountBase(BaseModel): + name: str = Field(..., min_length=1) + is_starred: bool + is_active: bool + + class Config: + fields = {"id_": "id"} + anystr_strip_whitespace = True + alias_generator = to_camel + + +class AccountIn(AccountBase): + type: int + is_reconcilable: bool + + +class Account(AccountIn): + id_: uuid.UUID + code: int + is_fixture: bool + + +class EmployeeIn(AccountBase): + designation: str + salary: int = Field(ge=0) + points: Decimal = Field(ge=0, lt=1000, multiple_of=0.01) + joining_date: date + leaving_date: Optional[date] + + @validator("joining_date", pre=True) + def parse_joining_date(cls, value): + return datetime.strptime(value, "%d-%b-%Y").date() + + @validator("leaving_date", pre=True) + def parse_leaving_date(cls, value): + if value is None or value == "": + return None + else: + return datetime.strptime(value, "%d-%b-%Y").date() + + @validator("leaving_date") + def leaving_date_more_than_joining_date(cls, v, values, **kwargs): + if values["is_active"]: + return None + if v < values["joining_date"]: + raise ValueError("Leaving Date cannot be less than Joining Date") + return v + + +class Employee(EmployeeIn): + id_: uuid.UUID + code: int + is_fixture: bool + + +class DbSetting(BaseModel): + id_: uuid.UUID + name: str + data: bytes + + +class AccountType(BaseModel): + id_: int + name: str + + class Config: + fields = {"id_": "id"} diff --git a/barker/scripts/fixtures.py b/barker/scripts/fixtures.py index 0b1aece..c7ec417 100644 --- a/barker/scripts/fixtures.py +++ b/barker/scripts/fixtures.py @@ -23,246 +23,12 @@ from barker.models import ( def usage(argv): cmd = os.path.basename(argv[0]) - print( - "usage: %s [var=value]\n" - '(example: "%s development.ini")' % (cmd, cmd) - ) + print("usage: %s [var=value]\n" '(example: "%s development.ini")' % (cmd, cmd)) sys.exit(1) def main(argv=sys.argv): - if len(argv) < 2: - usage(argv) - config_uri = argv[1] - options = parse_vars(argv[2:]) - setup_logging(config_uri) - settings = get_appsettings(config_uri, options=options) - - engine = get_engine(settings) - session_factory = get_session_factory(engine) - with transaction.manager: - dbsession = get_tm_session(session_factory, transaction.manager) - prod = True - if prod: - dbsession.add(Permission("Guest Book", uuid.UUID("7669dfc9-cc75-4e48-b267-145c8832a83c"))) - dbsession.add(Permission("Printers", uuid.UUID("5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c"))) - dbsession.add(Permission("Sections", uuid.UUID("c973f32c-a37b-496a-8dc5-60d2e4c39e97"))) - dbsession.add(Permission("Section Printers", uuid.UUID("7a04ba63-5d08-4078-9051-a6d91cce3e48"))) - else: - add_permissions(dbsession) - main_section = Section( - "Main", uuid.UUID("3f13f6e7-dc76-4fca-8fdb-b2bbf29b35df") - ) - dbsession.add(main_section) - mcs = [ - ModifierCategory( - "Old Modifiers", - 0, - 0, - True, - 0, - uuid.UUID("e046ad33-dc65-4c78-8833-c3d3538d44c0"), - ), - ModifierCategory( - "Bar Instructions", - 0, - 0, - True, - 0, - uuid.UUID("b572f401-3c2f-48b9-8973-ada5a6e4d3a6"), - ), - ModifierCategory( - "Delivery", - 0, - 0, - True, - 0, - uuid.UUID("caa72832-5034-405e-8442-68a8cc12ace9"), - ), - ModifierCategory( - "Kitchen Instructions", - 0, - 0, - True, - 0, - uuid.UUID("d6a0595f-e209-42e4-bb12-b7499f9a9c4d"), - ), - ModifierCategory( - "Mixers", - 0, - 0, - True, - 0, - uuid.UUID("60ca9122-adc5-463b-ad5f-33a68df8c3ae"), - ), - ModifierCategory( - "Pasta Sauce", - 0, - 0, - True, - 0, - uuid.UUID("ef5b1a0b-5eb1-45ff-bd82-3209c8b888df"), - ), - ] - for item in mcs: - dbsession.add(item) - options = [ - SettleOption("Unsettled", False, 1, True, 1), - SettleOption("Cash", True, 2, False, 2), - SettleOption("Credit Card", True, 2, True, 3), - SettleOption("No Charge", True, 3, True, 4), - SettleOption("Bill To Company", True, 2, True, 5), - SettleOption("Tip", True, 2, True, 6), - SettleOption("Round Off", False, 1, False, 7), - SettleOption("Amount", False, 1, False, 8), - SettleOption("Void", True, 1, True, 9), - SettleOption("Staff", True, 4, True, 10), - ] - for option in options: - dbsession.add(option) - dbsession.add( - Customer( - "", "Cash", "", "", uuid.UUID("2c716f4b-0736-429a-ad51-610d7c47cb5e") - ) - ) - dbsession.add( - DbSetting( - uuid.UUID("fb738ba2-a3c9-40ed-891c-b930e6454974"), - "Header", - { - "Text": """ Hops n Grains - The Microbrewery - SCO 358, Sector 9, Panchkula - A Unit of Peitho Foods Pvt. Ltd. - CIN: U15139CH2010PTC032202 -(Reg Add: Plot No. 907, Indl Area II, Chd) - TIN: 06592507323 - Service Tax: AAFCP5097GSD001 -""" - }, - ) - ) - dbsession.add( - DbSetting( - uuid.UUID("f7799871-d16e-4c4d-9b57-2299a5839acb"), - "Footer", - {"Text": "Call: 0172-4026666, 8054923853, 8054923856"}, - ) - ) - -def add_permissions(dbsession): - permissions = [ - Permission( - "Accounts Audit", uuid.UUID("f30fd1fb-df09-46f5-8c5d-181fd46f38de") - ), - Permission( - "Beer Consumption", uuid.UUID("efbb8f31-9631-4491-92f4-17cc98e6a0c0") - ), - Permission( - "Bill Details", uuid.UUID("612bb529-b50d-4653-a1c0-ebb725c7d728") - ), - Permission( - "Cashier Checkout", uuid.UUID("a86f8bcf-66f4-4c44-89e1-b714488b8331") - ), - Permission( - "Change Rate", uuid.UUID("10c63aae-0e48-4e54-b3b8-dd8a80b88fbf") - ), - Permission("Customers", uuid.UUID("e5fef133-cdbe-441f-bb54-1f0db0c5db79")), - Permission("Discount", uuid.UUID("1f66f131-0105-4466-8f8e-21e0ccc2ac27")), - Permission( - "Discount Report", uuid.UUID("0d8ba1d5-6731-417c-ab0e-be03cfdc96db") - ), - Permission( - "Edit Printed Bill", uuid.UUID("4ff6cb0f-93cb-4760-8219-4de280eaa957") - ), - Permission( - "Edit Printed Product", - uuid.UUID("959713be-d753-4e14-8ecd-e27f33587499"), - ), - Permission("Guest Book", uuid.UUID("7669dfc9-cc75-4e48-b267-145c8832a83c")), - Permission("Machines", uuid.UUID("f12b573f-edcb-490d-91c3-fa76f6502ffd")), - Permission("Merge Kots", uuid.UUID("bed774e9-4857-43b0-a4af-40230c9eb5db")), - Permission( - "Merge Tables", uuid.UUID("dfc493fb-ac14-4602-8596-f93f47b617de") - ), - Permission("Modifiers", uuid.UUID("9dc82529-1e86-41b4-a152-eaea9f775fea")), - Permission( - "Move Kot to New Table", - uuid.UUID("5ed5796a-ca99-437f-8f67-483b1ade81ed"), - ), - Permission("Move Table", uuid.UUID("cfdb69c9-d37a-40af-bef2-e29c04602543")), - Permission("NC Product", uuid.UUID("54263587-773e-4cbb-b1e4-4e814141158e")), - Permission("Open Bill", uuid.UUID("5811d233-a1ae-4d32-af52-cebbf46d274a")), - Permission("Owner", uuid.UUID("6d109b66-8452-42aa-bbe9-d4cef440b7a1")), - Permission("Print Bill", uuid.UUID("92242eae-bd38-4223-829b-2f981933b7f2")), - Permission("Print Kot", uuid.UUID("0eef56fb-7741-49fd-8b84-5069cccae767")), - Permission("Products", uuid.UUID("f1f892ed-34aa-4c50-be12-dbaf48be7d4c")), - Permission("Roles", uuid.UUID("d39f86f6-14e4-4fc3-b07e-01e2501a6f65")), - Permission("Sales", uuid.UUID("92ba45c4-2d34-4cbd-b5b8-d9164c3595d5")), - Permission( - "Sales Analysis", uuid.UUID("0c1acb7c-9116-46e2-a3be-9d632e811330") - ), - Permission( - "Sales Detail", uuid.UUID("e6476396-ef83-4c47-bc20-9f3b936813f9") - ), - Permission( - "Settle Bill", uuid.UUID("9f7b658a-25bc-4a53-8560-2dde1c7a188a") - ), - Permission("Split Bill", uuid.UUID("0a8cfaf4-624e-478f-be65-c3b6392078c7")), - Permission("Tables", uuid.UUID("ac4512e8-efdd-429e-a7ae-a34d18782663")), - Permission( - "Tax Analysis", uuid.UUID("bab36396-53dd-44ea-ab3c-426efa7830c8") - ), - Permission("Taxes", uuid.UUID("5c8fcdde-460d-4047-810f-e34fb899fadc")), - Permission("Users", uuid.UUID("243447b8-b403-47e6-8b3d-8e76f4df44a9")), - Permission("Void Bill", uuid.UUID("e3c76262-adc0-4936-8b4d-217c6292298b")), - Permission( - "Void or Reprinted Bill Report", - uuid.UUID("30c8e743-c710-42d7-843a-0b75543b3516"), - ), - Permission("Printers", uuid.UUID("5b66c6f6-003a-4ef8-ba28-49b8ff1ac33c")), - Permission("Sections", uuid.UUID("c973f32c-a37b-496a-8dc5-60d2e4c39e97")), - ] - - for permission in permissions: - dbsession.add(permission) - - roles = [ - Role("Owner", uuid.UUID("06ec0ddb-949c-4357-aefb-65e5e55a9ae7")), - Role("Accountant", uuid.UUID("57d4538c-257a-4bf4-9a42-342992cb6af3")), - Role("Bar Captain", uuid.UUID("5a8ebb05-4817-45a5-866f-e523c30bfa25")), - Role("Captain", uuid.UUID("8db7001f-0964-4607-84f5-b6f4d9183fef")), - Role("Cashier", uuid.UUID("f1f0b112-1404-4b55-b121-f07ee6e08d12")), - Role("Controller", uuid.UUID("d9a5a478-1fe4-4847-84da-63cfba1a094a")), - Role("Manager", uuid.UUID("90ea7b14-9057-4bfd-a7cf-0ee7a3bb2463")), - Role("Senior Captain", uuid.UUID("d9b1b433-1ed5-4109-8ab2-cbd48ff010cd")), - Role("Server", uuid.UUID("6b378b71-f091-4485-a589-8db94ff1d6a4")), - ] - - roles[0].permissions = permissions - roles[1].permissions = list( - permissions[i] for i in [2, 3, 11, 18, 24, 25, 26, 30, 34] - ) - roles[2].permissions = list(permissions[i] for i in [26]) - roles[3].permissions = list(permissions[i] for i in [16]) - roles[4].permissions = list(permissions[i] for i in [20, 24, 27]) - roles[5].permissions = list( - permissions[i] for i in [0, 2, 7, 11, 18, 22, 24, 25, 26, 34] - ) - roles[6].permissions = list( - permissions[i] - for i in [2, 3, 4, 5, 6, 8, 11, 14, 18, 22, 25, 26, 28, 29, 33, 34] - ) - roles[7].permissions = list(permissions[i] for i in [9, 12, 13, 15, 16]) - roles[8].permissions = list(permissions[i] for i in [21, 24]) - - for role in roles: - dbsession.add(role) - - admin = User("Admin", "123456", False) - admin.roles.append(roles[0]) - dbsession.add(admin) diff --git a/barker/scripts/initializedb.py b/barker/scripts/initializedb.py index e9c9850..b03a0de 100644 --- a/barker/scripts/initializedb.py +++ b/barker/scripts/initializedb.py @@ -45,14 +45,13 @@ from barker.models import ( User, user_roles, Voucher, - VoucherType + VoucherType, ) def usage(argv): cmd = os.path.basename(argv[0]) - print('usage: %s [var=value]\n' - '(example: "%s development.ini")' % (cmd, cmd)) + print("usage: %s [var=value]\n" '(example: "%s development.ini")' % (cmd, cmd)) sys.exit(1) diff --git a/barker/security/__init__.py b/barker/security/__init__.py deleted file mode 100644 index 3deec8e..0000000 --- a/barker/security/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -import uuid - -from pyramid.authentication import AuthTktAuthenticationPolicy -from barker.security.permission_authorization_policy import PermissionAuthorizationPolicy -from ..models.auth import User - - -def get_user(request): - user_id = request.unauthenticated_userid - if user_id is not None: - user = request.dbsession.query(User).get(user_id) - return user - - -def groupfinder(user_id, request): - if 'perms' in request.session: - perms = request.session['perms'] - else: - perms = [] - user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one() - for role in user.roles: - for perm in role.permissions: - perms.append(perm.name) - perms = sorted(f7(perms)) - request.session['perms'] = perms - return perms - - -def f7(seq): - seen = set() - seen_add = seen.add - return [x for x in seq if x not in seen and not seen_add(x)] - - -def includeme(config): - authn_policy = AuthTktAuthenticationPolicy('barker', timeout=900, reissue_time=90, callback=groupfinder) - config.set_authentication_policy(authn_policy) - config.set_authorization_policy(PermissionAuthorizationPolicy()) - config.add_request_method(get_user, 'user', reify=True) diff --git a/barker/security/permission_authorization_policy.py b/barker/security/permission_authorization_policy.py deleted file mode 100644 index c709947..0000000 --- a/barker/security/permission_authorization_policy.py +++ /dev/null @@ -1,27 +0,0 @@ -from zope.interface import implementer - -from pyramid.interfaces import IAuthorizationPolicy - - -@implementer(IAuthorizationPolicy) -class PermissionAuthorizationPolicy(object): - def permits(self, context, principals, permission): - if isinstance(permission, str): - return self.check(principals, permission) - for p in permission: - if self.check(principals, p): - return True - return False - - def check(self, principals, permission): - if permission == "Authenticated": - permission = "system.Authenticated" - if permission == "Everyone": - permission = "system.Everyone" - allowed = permission in principals - return allowed - - def principals_allowed_by_permission(self, context, permission): - allowed = set() - allowed.add(permission) - return allowed diff --git a/barker/subscribers.py b/barker/subscribers.py index 75b7843..28b98a6 100644 --- a/barker/subscribers.py +++ b/barker/subscribers.py @@ -5,6 +5,6 @@ from barker.models.master import DbSetting @subscriber(NewRequest) def maintenance_mode(event): - maintenance = event.request.dbsession.query(DbSetting).filter(DbSetting.name == 'Maintenance').first() + maintenance = event.request.dbsession.query(DbSetting).filter(DbSetting.name == "Maintenance").first() if maintenance is not None and maintenance.data != event.request.authenticated_userid: raise HTTPServiceUnavailable diff --git a/barker/transactional_view_deriver.py b/barker/transactional_view_deriver.py deleted file mode 100644 index 51dca5b..0000000 --- a/barker/transactional_view_deriver.py +++ /dev/null @@ -1,38 +0,0 @@ -import transaction -from pyramid.response import Response -from sqlalchemy.exc import OperationalError, IntegrityError, DBAPIError -from barker.models.validation_exception import ValidationError - - -def transactional_view(view, info): - if info.options.get("trans"): - - def wrapper_view(context, request): - try: - response = view(context, request) - except ( - ValidationError, - ValueError, - KeyError, - AttributeError, - TypeError, - OperationalError, - IntegrityError, - DBAPIError, - ) as ex: - transaction.abort() - response = Response() - response.status_int = 500 - response.content_type = "application/json" - response.json = {"Error": "Failed validation: {0!s}".format(ex)} - return response - - return wrapper_view - return view - - -# def transactional_view(view, info): -# return view - - -transactional_view.options = ("trans",) diff --git a/barker/views/__init__.py b/barker/views/__init__.py deleted file mode 100644 index f8386a6..0000000 --- a/barker/views/__init__.py +++ /dev/null @@ -1,64 +0,0 @@ -from decimal import Decimal -import uuid -import re - -import pkg_resources -from pyramid.httpexceptions import HTTPFound - -from barker.exceptions import ValidationFailure -from pyramid.response import Response, FileResponse -from pyramid.view import forbidden_view_config, exception_view_config, view_config - - -@view_config(route_name="home") -@view_config(request_method="GET", route_name="login") -def home(request): - package, resource = "barker:static/index.html".split(":", 1) - file = pkg_resources.resource_filename(package, resource) - return FileResponse(file, request=request) - - -@forbidden_view_config() -def forbidden(request): - if request.accept.quality("application/json") == 1: - response = Response("Forbidden") - response.status_int = 401 - return response - else: - ret = HTTPFound( - location=request.route_url("login", _query={"returnUrl": request.path_qs}) - ) - return ret - return response - - -@exception_view_config(ValidationFailure) -def failed_validation(exc, request): - response = Response() - response.status_int = 500 - response.content_type = 'application/json' - response.json = {'Error': "Failed validation: {0!s}".format(exc.message)} - return response - - -def to_uuid(value): - p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$') - return uuid.UUID(value) if p.match(value) else None - - -def to_decimal(value, default=0): - import re - _parser = re.compile(r""" # A numeric string consists of: - (?P[-+])? # an optional sign, followed by either... - ( - (?=\d|\.\d) # ...a number (with at least one digit) - (?P\d*) # having a (possibly empty) integer part - (\.(?P\d*))? # followed by an optional fractional part - | - (?Ps)? # ...an (optionally signaling) - NaN # NaN - (?P\d*) # with (possibly empty) diagnostic info. - ) - \Z - """, re.VERBOSE | re.IGNORECASE).match - return Decimal(value) if _parser(value.strip()) is not None else default diff --git a/barker/views/customer.py b/barker/views/customer.py deleted file mode 100644 index e476af2..0000000 --- a/barker/views/customer.py +++ /dev/null @@ -1,74 +0,0 @@ -import uuid - -import transaction -from pyramid.view import view_config - -from barker.models import Customer - - -@view_config(request_method='PUT', route_name='v1_customers_new', renderer='json', permission='Customers', trans=True) -def save(request): - json = request.json_body - item = Customer(json['company'], json['name'], json['phone'], json['address'], json['important']) - request.dbsession.add(item) - transaction.commit() - item = request.dbsession.query(Customer).filter(Customer.id == item.id).first() - return customer_info(item) - - -@view_config(request_method='POST', route_name='v1_customers_id', renderer='json', permission='Customers', trans=True) -def update(request): - json = request.json_body - item = request.dbsession.query(Customer).filter(Customer.id == uuid.UUID(request.matchdict['id'])).first() - item.company = json['company'] - item.name = json['name'] - item.phone = json['phone'] - item.address = json['address'] - item.is_important = json['important'] - transaction.commit() - item = request.dbsession.query(Customer).filter(Customer.id == item.id).first() - return customer_info(item) - - -@view_config(request_method='DELETE', route_name='v1_customers_id', renderer='json', permission='Customers', trans=True) -def delete(request): - item = request.dbsession.query(Customer).filter(Customer.id == uuid.UUID(request.matchdict['id'])).first() - request.dbsession.delete(item) - transaction.commit() - return {} - - -@view_config(request_method='GET', route_name='v1_customers_id', renderer='json', permission='Authenticated') -def show_id(request): - id_ = uuid.UUID(request.matchdict['id']) - item = request.dbsession.query(Customer).filter(Customer.id == id_).first() - return customer_info(item) - - -@view_config(request_method='GET', route_name='v1_customers_list', renderer='json', permission='Authenticated') -def show_list(request): - list_ = request.dbsession.query(Customer).order_by(Customer.name).all() - customers = [] - for item in list_: - customers.append({ - 'id': item.id, - 'company': item.company, - 'name': item.name, - 'address': item.address, - 'important': item.is_important, - 'phone': item.phone, - 'remarks': '' - }) - return customers - - -def customer_info(item): - return { - 'id': item.id, - 'company': item.company, - 'name': item.name, - 'address': item.address, - 'important': item.is_important, - 'phone': item.phone, - 'remarks': '' - } diff --git a/barker/views/login.py b/barker/views/login.py deleted file mode 100644 index 569cf8e..0000000 --- a/barker/views/login.py +++ /dev/null @@ -1,80 +0,0 @@ -import uuid - -import transaction - -from pyramid.httpexceptions import HTTPFound -from pyramid.response import Response -from pyramid.security import forget, remember -from pyramid.view import view_config - -from barker.models import User -from barker.security import f7 - - -@view_config(route_name='logout') -def logout(request): - request.session.invalidate() - headers = forget(request) - return HTTPFound(location=request.route_url('home'), headers=headers) - - -@view_config(request_method="POST", route_name="logout", renderer="json") -def api_logout(request): - request.session.invalidate() - request.response.headers = forget(request) - return {"isAuthenticated": False, "perms": {}} - - -@view_config(request_method='POST', route_name='v1_login', renderer='json', trans=True) -def login(request): - username = request.json_body.get('name', None) - password = request.json_body.get('password', None) - found, user = User.auth(username, password, request.dbsession) - - if found: - headers = remember(request, str(user.id)) - auth = { - 'id': str(user.id), - 'name': user.name, - 'lockedOut': user.locked_out, - 'isAuthenticated': True, - 'perms': sorted(f7([p.name for r in user.roles for p in r.permissions])) - } - request.response.headers = headers - request.response.content_type = 'application/json' - request.response.json = auth - return request.response - elif not found: - response = Response() - response.status_int = 401 - response.content_type = 'application/json' - response.json = {'Error': 'Login Failed'} - transaction.abort() - return response - - -def get_permissions(user): - perms = [] - for role in user.roles: - for perm in role.permissions: - perms.append({'PermissionID': str(perm.id), 'Name': perm.name}) - return sorted({p['PermissionID']: p for p in perms}.values(), key=lambda i: i['Name']) - - -@view_config(route_name='v1_auth', renderer='json') -def user_permission(request): - user_id = request.authenticated_userid - if user_id is None: - auth = {'isAuthenticated': False, 'perms': {}} - elif 'auth' in request.session: - auth = request.session['auth'] - else: - user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one() - auth = { - 'id': user.id, - 'name': user.name, - 'isAuthenticated': True, - 'perms': sorted(f7([p.name for r in user.roles for p in r.permissions])) - } - request.session['auth'] = auth - return auth diff --git a/barker/views/menu_category.py b/barker/views/menu_category.py deleted file mode 100644 index 4c0aaa0..0000000 --- a/barker/views/menu_category.py +++ /dev/null @@ -1,216 +0,0 @@ -import uuid -from decimal import Decimal, InvalidOperation - -import transaction -from pyramid.response import Response -from pyramid.view import view_config - -from barker.exceptions import ValidationFailure -from barker.models import Product, MenuCategory -from barker.models.validation_exception import ValidationError - - -@view_config( - request_method="POST", - route_name="v1_menu_categories_new", - renderer="json", - permission="Products", - trans=True, -) -def save(request): - json = request.json_body - name = json.get("name", "").strip() - if name == "": - raise ValidationError("Name cannot be blank") - try: - discount_limit = Decimal(json["discountLimit"]) / 100 - if discount_limit < 0 or discount_limit > 1: - raise ValidationError("Tax Rate must be a decimal >= 0 and <= 100") - except (ValueError, InvalidOperation): - raise ValidationError("Tax Rate must be a decimal >= 0 and <= 100") - is_active = json.get("isActive", True) - item = MenuCategory(name, discount_limit, is_active, 0) - request.dbsession.add(item) - transaction.commit() - return menu_category_info(item.id, request.dbsession) - - -@view_config( - request_method="PUT", - route_name="v1_menu_categories_id", - renderer="json", - permission="Products", - trans=True, -) -def update(request): - json = request.json_body - item = ( - request.dbsession.query(MenuCategory) - .filter(MenuCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) - item.name = json["name"].strip() - try: - item.discount_limit = Decimal(json["discountLimit"]) / 100 - if item.discount_limit < 0 or item.discount_limit > 1: - raise ValidationError("Tax Rate must be a decimal >= 0 and <= 100") - except (ValueError, InvalidOperation): - raise ValidationError("Tax Rate must be a decimal >= 0 and <= 100") - item.is_active = json.get("isActive", True) - transaction.commit() - return menu_category_info(item.id, request.dbsession) - - -@view_config( - request_method="DELETE", - route_name="v1_menu_categories_id", - renderer="json", - permission="Products", - trans=True, -) -def delete(request): - item = ( - request.dbsession.query(MenuCategory) - .filter(MenuCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item is None: - response = Response("Menu Category not Found") - response.status_int = 500 - return response - elif item.is_fixture: - transaction.abort() - raise ValidationFailure( - "{0} is a fixture and cannot be edited or deleted.".format(item.name) - ) - else: - response = Response("Menu Category deletion not implemented") - response.status_int = 500 - return response - - -@view_config( - request_method="GET", - route_name="v1_menu_categories_new", - renderer="json", - permission="Menu Categories", -) -def show_blank(request): - return menu_category_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_menu_categories_id", - renderer="json", - permission="Products", -) -def show_id(request): - return menu_category_info(uuid.UUID(request.matchdict["id"]), request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_menu_categories_list", - renderer="json", - permission="Authenticated", -) -def show_list(request): - list_ = ( - request.dbsession.query(MenuCategory) - .order_by(MenuCategory.sort_order) - .order_by(MenuCategory.name) - .all() - ) - menu_categories = [] - for item in list_: - menu_categories.append(menu_category_info(item, request.dbsession)) - return menu_categories - - -@view_config( - request_method="GET", - route_name="v1_menu_categories_list", - renderer="json", - request_param="s", - permission="Authenticated", -) -def sale_list(request): - list_ = ( - request.dbsession.query(MenuCategory) - .filter(MenuCategory.is_active == True) - .order_by(MenuCategory.sort_order) - .order_by(MenuCategory.name) - .all() - ) - menu_categories = [] - for item in list_: - products = ( - request.dbsession.query(Product) - .filter(Product.menu_category_id == item.id) - .filter(Product.is_active == True) - .order_by(Product.sort_order) - .order_by(Product.name) - .all() - ) - if len(products) == 0: - continue - pg = menu_category_info(item, request.dbsession) - pg["products"] = [ - { - "id": p.id, - "name": p.name, - "units": p.units, - "tat": {"id": p.vat.id, "name": p.vat.name, "rate": p.vat.rate}, - "price": p.price, - "hasHappyHour": p.has_happy_hour, - "isActive": p.is_active, - "isNotAvailable": p.is_not_available, - "sortOrder": p.sort_order, - "quantity": p.quantity, - } - for p in products - ] - menu_categories.append(pg) - return menu_categories - - -@view_config( - request_method="POST", - route_name="v1_menu_categories_list", - renderer="json", - permission="Products", - trans=True, -) -def sort_order(request): - json = request.json_body - for index, item in enumerate(json): - request.dbsession.query(MenuCategory).filter( - MenuCategory.id == uuid.UUID(item["id"]) - ).update({MenuCategory.sort_order: index}) - return True - - -def menu_category_info(item, dbsession): - if item is None: - return { - "name": "", - "discountLimit": 0, - "isActive": True, - "isFixture": False, - "sortOrder": 0, - } - if type(item) is uuid.UUID: - item = dbsession.query(MenuCategory).filter(MenuCategory.id == item).first() - return { - "id": item.id, - "name": item.name, - "discountLimit": item.discount_limit * 100, - "isActive": item.is_active, - "isFixture": item.is_fixture, - "sortOrder": item.sort_order, - } diff --git a/barker/views/modifier_category.py b/barker/views/modifier_category.py deleted file mode 100644 index 68068fa..0000000 --- a/barker/views/modifier_category.py +++ /dev/null @@ -1,280 +0,0 @@ -import uuid -from functools import reduce - -import transaction - -from pyramid.view import view_config - -from barker.models import ModifierCategory, Product, MenuCategory -from barker.models.validation_exception import ValidationError - - -@view_config( - request_method="POST", - route_name="v1_modifier_categories_new", - renderer="json", - permission="Modifiers", - trans=True, -) -def save(request): - json = request.json_body - name = json.get("name", "").strip() - if name == "": - raise ValidationError("Name cannot be blank") - try: - minimum = int(json.get("minimum", 0)) - if minimum < 0: - raise ValidationError("Minimum must be an integer >= 0") - except ValueError: - raise ValidationError("Minimum must be an integer >= 0") - try: - maximum = json.get("maximum", None) - if maximum is not None: - maximum = int(maximum) - if maximum < 0: - raise ValidationError( - "Maximum must be an integer and cannot be less than zero" - ) - elif maximum == 0: - maximum = None - except ValueError: - raise ValidationError("Maximum must be an integer and cannot be less than zero") - is_active = json.get("isActive", True) - item = ModifierCategory(name, minimum, maximum, is_active) - request.dbsession.add(item) - add_products(item, json["menuCategories"], request.dbsession) - transaction.commit() - return modifier_category_info(item.id, request.dbsession) - - -@view_config( - request_method="PUT", - route_name="v1_modifier_categories_id", - renderer="json", - permission="Modifiers", - trans=True, -) -def update(request): - item = ( - request.dbsession.query(ModifierCategory) - .filter(ModifierCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - json = request.json_body - item.name = json["name"].strip() - if item.name == "": - raise ValidationError("Name cannot be blank") - try: - item.minimum = int(json.get("minimum", 0)) - if item.minimum < 0: - raise ValidationError("Minimum must be an integer >= 0") - except ValueError: - raise ValidationError("Minimum must be an integer >= 0") - try: - item.maximum = json.get("maximum", None) - if item.maximum is not None: - item.maximum = int(item.maximum) - if item.maximum < 0: - raise ValidationError( - "Maximum must be an integer and cannot be less than zero" - ) - elif item.maximum == 0: - item.maximum = None - except ValueError: - raise ValidationError("Maximum must be an integer and cannot be less than zero") - item.is_active = json["isActive"] - add_products(item, json["menuCategories"], request.dbsession) - transaction.commit() - return modifier_category_info(item.id, request.dbsession) - - -@view_config( - request_method="DELETE", - route_name="v1_modifier_categories_id", - renderer="json", - permission="Modifiers", - trans=True, -) -def delete(request): - item = ( - request.dbsession.query(ModifierCategory) - .filter(ModifierCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - request.dbsession.delete(item) - transaction.commit() - return {None, request.dbsession} - - -@view_config( - request_method="GET", - route_name="v1_modifier_categories_id", - renderer="json", - permission="Authenticated", -) -def show_id(request): - id_ = uuid.UUID(request.matchdict["id"]) - return modifier_category_info(id_, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_modifier_categories_new", - renderer="json", - permission="Authenticated", -) -def show_blank(request): - return modifier_category_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_modifier_categories_list", - renderer="json", - permission="Authenticated", -) -def show_list(request): - list_ = ( - request.dbsession.query(ModifierCategory) - .order_by(ModifierCategory.sort_order) - .order_by(ModifierCategory.name) - .all() - ) - menu_categories = ( - request.dbsession.query(MenuCategory) - .join(MenuCategory.products) - .filter(Product.is_active == True) - .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) - .all() - ) - modifier_categories = [] - for item in list_: - modifier_category = { - "id": item.id, - "name": item.name, - "minimum": item.minimum, - "maximum": item.maximum, - "isActive": item.is_active, - "menuCategories": [ - { - "id": mc.id, - "name": mc.name, - "enabled": reduce( - lambda x, y: x and (y in item.products), mc.products, True - ), - "products": [ - {"id": p.id, "name": p.name} - for p in mc.products - if p in item.products - ], - } - for mc in menu_categories - ], - } - modifier_category["menuCategories"] = [ - i for i in modifier_category["menuCategories"] if len(i["products"]) > 0 - ] - modifier_categories.append(modifier_category) - return modifier_categories - - -@view_config( - request_method="GET", - route_name="v1_modifier_categories_list", - renderer="json", - request_param="p", - permission="Authenticated", -) -def show_for_product(request): - product_id = uuid.UUID(request.GET["p"]) - product = request.dbsession.query(Product).filter(Product.id == product_id).first() - - return [ - { - "id": item.id, - "name": item.name, - "minimum": item.minimum, - "maximum": item.maximum, - "isActive": item.is_active, - "modifiers": [ - {"id": m.id, "name": m.name, "price": m.price} - for m in item.modifiers - if m.is_active == True - ], - } - for item in product.modifier_categories - if item.is_active == True - ] - - -def modifier_category_info(item, dbsession): - menu_categories = ( - dbsession.query(MenuCategory) - .join(MenuCategory.products) - .filter(Product.is_active == True) - .order_by(MenuCategory.sort_order, Product.sort_order, Product.name) - .all() - ) - if item is None: - return { - "name": "", - "minimum": 0, - "maximum": 0, - "isActive": True, - "menuCategories": [ - { - "id": mc.id, - "name": mc.name, - "enabled": False, - "products": [ - {"id": p.id, "name": p.name, "enabled": False} - for p in mc.products - ], - } - for mc in menu_categories - ], - } - if type(item) is uuid.UUID: - item = ( - dbsession.query(ModifierCategory) - .filter(ModifierCategory.id == item) - .first() - ) - return { - "id": item.id, - "name": item.name, - "minimum": item.minimum, - "maximum": item.maximum, - "isActive": item.is_active, - "menuCategories": [ - { - "id": mc.id, - "name": mc.name, - "enabled": False, - "products": [ - { - "id": p.id, - "name": p.name, - "enabled": True if p in item.products else False, - } - for p in mc.products - ], - } - for mc in menu_categories - ], - } - - -def add_products(modifier_category, menu_categories, dbsession): - for mc in menu_categories: - for p in mc["products"]: - id_ = uuid.UUID(p["id"]) - old = [p for p in modifier_category.products if p.id == id_] - old = None if len(old) == 0 else old[0] - if p["enabled"] and old is None: - product_object = ( - dbsession.query(Product).filter(Product.id == id_).one() - ) - modifier_category.products.append(product_object) - elif not p["enabled"] and old: - modifier_category.products.remove(old) diff --git a/barker/views/product.py b/barker/views/product.py deleted file mode 100644 index 100560b..0000000 --- a/barker/views/product.py +++ /dev/null @@ -1,295 +0,0 @@ -import uuid -from decimal import Decimal, InvalidOperation - -import transaction -from pyramid.response import Response -from pyramid.view import view_config - -from barker.models import Product -from barker.models.validation_exception import ValidationError - - -@view_config( - request_method="POST", - route_name="v1_products_new", - renderer="json", - permission="Products", - trans=True, -) -def save(request): - json = request.json_body - - name = json.get("name", "").strip() - if name == "": - raise ValidationError("Name cannot be blank") - - units = json.get("units", "").strip() - - menu_category = json.get("menuCategory", None) - if menu_category is None: - raise ValidationError("please choose a menu category") - menu_category_id = uuid.UUID(menu_category["id"]) - - sale_category = json.get("saleCategory", None) - if sale_category is None: - raise ValidationError("please choose a sale category") - sale_category_id = uuid.UUID(sale_category["id"]) - - try: - price = Decimal(json.get("price", 0)) - if price < 0: - raise ValidationError("Price must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Price must be a decimal >= 0") - - has_happy_hour = json.get("hasHappyHour", True) - is_not_available = json.get("isNotAvailable", True) - - try: - quantity = Decimal(json.get("quantity", 0)) - if quantity < 0: - raise ValidationError("Quantity must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Quantity must be a decimal >= 0") - - is_active = json.get("isActive", True) - - item = Product( - name, - units, - menu_category_id, - sale_category_id, - price, - has_happy_hour, - is_not_available, - quantity, - is_active, - ) - request.dbsession.add(item) - transaction.commit() - return product_info(item.id, request.dbsession) - - -@view_config( - request_method="PUT", - route_name="v1_products_id", - renderer="json", - permission="Products", - trans=True, -) -def update(request): - item = ( - request.dbsession.query(Product) - .filter(Product.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - json = request.json_body - item.name = json["name"].strip() - if item.name == "": - raise ValidationError("Name cannot be blank") - item.units = json["units"].strip() - item.menu_category_id = uuid.UUID(json["menuCategory"]["id"]) - item.sale_category_id = uuid.UUID(json["saleCategory"]["id"]) - try: - item.price = Decimal(json["price"]) - if item.price < 0: - raise ValidationError("Price must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Price must be a decimal >= 0") - item.has_happy_hour = json["hasHappyHour"] - item.is_not_available = json["isNotAvailable"] - try: - item.quantity = Decimal(json["quantity"]) - if item.price < 0: - raise ValidationError("Quantity must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Quantity must be a decimal >= 0") - item.is_active = json["isActive"] - transaction.commit() - return product_info(item.id, request.dbsession) - - -@view_config( - request_method="DELETE", - route_name="v1_products_id", - renderer="json", - permission="Products", - trans=True, -) -def delete(request): - item = ( - request.dbsession.query(Product) - .filter(Product.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item is None: - response = Response("Product not Found") - response.status_int = 500 - return response - else: - response = Response("Product deletion not implemented") - response.status_int = 500 - return response - - -@view_config( - request_method="GET", - route_name="v1_products_new", - renderer="json", - permission="Authenticated", -) -def show_blank(request): - return product_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_products_id", - renderer="json", - permission="Authenticated", -) -def show_id(request): - id_ = uuid.UUID(request.matchdict["id"]) - return product_info(id_, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_products_list", - renderer="json", - permission="Authenticated", -) -def show_list(request): - active = request.GET.get("a", None) - list_ = request.dbsession.query(Product) - if active is not None: - list_ = list_.filter(Product.is_active == active) - list_ = ( - list_.order_by(Product.menu_category_id, Product.sort_order) - .order_by(Product.name) - .all() - ) - products = [] - for item in list_: - products.append(product_info(item, request.dbsession)) - return products - - -@view_config( - request_method="GET", - route_name="v1_products_list", - renderer="json", - request_param=("mc", "a"), - permission="Authenticated", -) -def show_list_sale(request): - mc_id = uuid.UUID(request.GET["mc"]) - list_ = ( - request.dbsession.query(Product) - .filter(Product.is_active == True, Product.menu_category_id == mc_id) - .order_by(Product.sort_order, Product.name) - .all() - ) - products = [] - for item in list_: - products.append( - { - "id": item.id, - "name": item.full_name, - "saleCategory": { - "id": item.sale_category_id, - "name": item.sale_category.name, - }, - "tax": { - "id": item.sale_category.tax_id, - "name": item.sale_category.tax.name, - "rate": item.sale_category.tax.rate, - }, - "price": item.price, - "hasHappyHour": False, - "isNotAvailable": item.is_not_available, - "isActive": item.is_active, - "sortOrder": item.sort_order, - } - ) - if item.has_happy_hour: - products.append( - { - "id": item.id, - "name": "H H " + item.full_name, - "saleCategory": { - "id": item.sale_category_id, - "name": item.sale_category.name, - }, - "tax": { - "id": item.sale_category.tax_id, - "name": item.sale_category.tax.name, - "rate": item.sale_category.tax.rate, - }, - "price": item.price, - "hasHappyHour": True, - "isNotAvailable": item.is_not_available, - "isActive": item.is_active, - "sortOrder": item.sort_order, - } - ) - return products - - -@view_config( - request_method="POST", - route_name="v1_products_list", - renderer="json", - permission="Products", - trans=True, -) -def sort_order(request): - json = request.json_body - indexes = {} - for item in json: - product_id = uuid.UUID(item["id"]) - menu_category_id = uuid.UUID(item["menuCategory"]["id"]) - if menu_category_id in indexes: - indexes[menu_category_id] += 1 - else: - indexes[menu_category_id] = 0 - request.dbsession.query(Product).filter(Product.id == product_id).update( - {Product.sort_order: indexes[menu_category_id]} - ) - return True - - -def product_info(item, dbsession): - if item is None: - return { - "name": "", - "units": "", - "menuCategory": {}, - "saleCategory": {}, - "price": 0, - "hasHappyHour": False, - "isNotAvailable": False, - "isActive": True, - "sortOrder": 0, - } - if type(item) is uuid.UUID: - item = dbsession.query(Product).filter(Product.id == item).first() - return { - "id": item.id, - "name": item.name, - "units": item.units, - "menuCategory": {"id": item.menu_category_id, "name": item.menu_category.name}, - "saleCategory": { - "id": item.sale_category_id, - "name": item.sale_category.name, - "tax": { - "id": item.sale_category.tax_id, - "name": item.sale_category.tax.name, - }, - }, - "price": item.price, - "hasHappyHour": item.has_happy_hour, - "isNotAvailable": item.is_not_available, - "isActive": item.is_active, - "sortOrder": item.sort_order, - } diff --git a/barker/views/sale_category.py b/barker/views/sale_category.py deleted file mode 100644 index f39708f..0000000 --- a/barker/views/sale_category.py +++ /dev/null @@ -1,143 +0,0 @@ -import uuid - -import transaction -from pyramid.response import Response -from pyramid.view import view_config - -from barker.models import SaleCategory -from barker.models.validation_exception import ValidationError - - -@view_config( - request_method="POST", - route_name="v1_sale_categories_new", - renderer="json", - permission="Products", - trans=True, -) -def save(request): - json = request.json_body - name = json.get("name", "").strip() - if name == "": - raise ValidationError("Name cannot be blank") - tax = json.get("tax", None) - if tax is None: - raise ValidationError("please choose a tax") - tax_id = uuid.UUID(tax["id"]) - item = SaleCategory(name, tax_id) - request.dbsession.add(item) - transaction.commit() - return sale_category_info(item.id, request.dbsession) - - -@view_config( - request_method="PUT", - route_name="v1_sale_categories_id", - renderer="json", - permission="Products", - trans=True, -) -def update(request): - json = request.json_body - item = ( - request.dbsession.query(SaleCategory) - .filter(SaleCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) - item.name = json["name"].strip() - item.tax_id = uuid.UUID(json["tax"]["id"]) - transaction.commit() - return sale_category_info(item.id, request.dbsession) - - -@view_config( - request_method="DELETE", - route_name="v1_sale_categories_id", - renderer="json", - permission="Products", - trans=True, -) -def delete(request): - item = ( - request.dbsession.query(SaleCategory) - .filter(SaleCategory.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item is None: - response = Response("Sale Category not Found") - response.status_int = 500 - return response - else: - response = Response("Sale Category deletion not implemented") - response.status_int = 500 - return response - - -@view_config( - request_method="GET", - route_name="v1_sale_categories_new", - renderer="json", - permission="Authenticated", -) -def show_blank(request): - return sale_category_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_sale_categories_id", - renderer="json", - permission="Authenticated", -) -def show_id(request): - return sale_category_info(uuid.UUID(request.matchdict["id"]), request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_sale_categories_list", - renderer="json", - permission="Authenticated", -) -def show_list(request): - list_ = ( - request.dbsession.query(SaleCategory) - .order_by(SaleCategory.name) - .all() - ) - return [sale_category_info(item, request.dbsession) for item in list_] - - -@view_config( - request_method="GET", - route_name="v1_sale_categories_list", - renderer="json", - request_param="d", - permission="Authenticated", -) -def show_list_for_discount(request): - list_ = ( - request.dbsession.query(SaleCategory) - .order_by(SaleCategory.name) - .all() - ) - return [{"id": item.id, "name": item.name, "discount": 0} for item in list_] - - -def sale_category_info(item, dbsession): - if item is None: - return { - "name": "", - "tax": {} - } - if type(item) is uuid.UUID: - item = dbsession.query(SaleCategory).filter(SaleCategory.id == item).first() - return { - "id": item.id, - "name": item.name, - "tax": {"id": item.tax_id, "name": item.tax.name, "rate": item.tax.rate} - } diff --git a/barker/views/setting.py b/barker/views/setting.py deleted file mode 100644 index 2a0235f..0000000 --- a/barker/views/setting.py +++ /dev/null @@ -1,10 +0,0 @@ -from pyramid.view import view_config - -from barker.models import DbSetting - - -@view_config(request_method='GET', route_name='v1_settings_id', renderer='json', permission='Authenticated') -def show_id(request): - name = request.matchdict['id'] - item = request.dbsession.query(DbSetting).filter(DbSetting.name == name).first() - return {'SettingID': item.id, 'Name': item.name, 'Details': item.data} diff --git a/barker/views/tax.py b/barker/views/tax.py deleted file mode 100644 index 91416a6..0000000 --- a/barker/views/tax.py +++ /dev/null @@ -1,141 +0,0 @@ -import uuid -from decimal import Decimal, InvalidOperation - -import transaction -from pyramid.view import view_config - -from barker.models import Tax -from barker.models.validation_exception import ValidationError - - -@view_config( - request_method="POST", - route_name="v1_taxes_new", - renderer="json", - permission="Taxes", - trans=True, -) -def save(request): - json = request.json_body - name = json.get("name", "").strip() - if name == "": - raise ValidationError("Name cannot be blank") - try: - rate = Decimal(json["rate"]) / 100 - if rate < 0: - raise ValidationError("Tax Rate must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Tax Rate must be a decimal >= 0") - item = Tax(name, rate) - request.dbsession.add(item) - transaction.commit() - return tax_info(item.id, request.dbsession) - - -@view_config( - request_method="PUT", - route_name="v1_taxes_id", - renderer="json", - permission="Taxes", - trans=True, -) -def update(request): - json = request.json_body - item = ( - request.dbsession.query(Tax) - .filter(Tax.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) - item.name = json("name", "").strip() - if item.name == "": - raise ValidationError("Name cannot be blank") - try: - item.rate = Decimal(json["rate"]) / 100 - if item.rate <= 0: - raise ValidationError("Tax Rate must be a decimal >= 0") - except (ValueError, InvalidOperation): - raise ValidationError("Tax Rate must be a decimal >= 0") - transaction.commit() - item = request.dbsession.query(Tax).filter(Tax.id == item.id).first() - return tax_info(item.id, request.dbsession) - - -@view_config( - request_method="DELETE", - route_name="v1_taxes_id", - renderer="json", - permission="Taxes", - trans=True, -) -def delete(request): - item = ( - request.dbsession.query(Tax) - .filter(Tax.id == uuid.UUID(request.matchdict["id"])) - .first() - ) - if item.is_fixture: - raise ValidationError( - "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) - ) - request.dbsession.delete(item) - transaction.commit() - return tax_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_taxes_new", - renderer="json", - permission="Authenticated", -) -def show_blank(request): - return tax_info(None, request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_taxes_id", - renderer="json", - permission="Authenticated", -) -def show_id(request): - return tax_info(uuid.UUID(request.matchdict["id"]), request.dbsession) - - -@view_config( - request_method="GET", - route_name="v1_taxes_list", - renderer="json", - permission="Authenticated", -) -def show_list(request): - list_ = request.dbsession.query(Tax).order_by(Tax.name).all() - taxes = [] - for item in list_: - taxes.append( - { - "id": item.id, - "name": item.name, - "rate": item.rate, - "isFixture": item.is_fixture, - } - ) - return taxes - - -def tax_info(id_, dbsession): - if id_ is None: - tax = {"name": "", "rate": 0, "isFixture": False} - else: - item = dbsession.query(Tax).filter(Tax.id == id_).first() - tax = { - "id": item.id, - "name": item.name, - "rate": item.rate * 100, - "isFixture": item.is_fixture, - } - return tax diff --git a/barker/views/user.py b/barker/views/user.py deleted file mode 100644 index 29ec013..0000000 --- a/barker/views/user.py +++ /dev/null @@ -1,140 +0,0 @@ -import re -import uuid - -import transaction -from pyramid.response import Response -from pyramid.view import view_config - -from barker.exceptions import ValidationFailure -from barker.models import Role, User - - -@view_config(request_method='POST', route_name='v1_users_new', renderer='json', permission='Users', trans=True) -def save(request): - json = request.json_body - item = User(json['name'], json['password'], json['lockedOut']) - request.dbsession.add(item) - add_roles(item, json['roles'], request.dbsession) - transaction.commit() - return user_info(item.id, request.dbsession, request.has_permission('Users')) - - -@view_config(request_method='PUT', route_name='v1_users_id', renderer='json', permission='Users', trans=True) -def update(request): - json = request.json_body - id_ = request.matchdict['id'] - p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$') - if p.match(id_): - item = request.dbsession.query(User).filter(User.id == uuid.UUID(id_)).one() - else: - item = request.dbsession.query(User).filter(User.name.ilike(id_)).first() - if item is None: - raise ValidationFailure('User name / id not found') - if request.has_permission('Users'): - item.name = json['name'] - item.locked_out = json['lockedOut'] - add_roles(item, json['roles'], request.dbsession) - - if json['password'] != '' and json['password'] != item.password: - item.password = json['password'] - transaction.commit() - return user_info(item.id, request.dbsession, request.has_permission('Users')) - - -@view_config(request_method='DELETE', route_name='v1_users_id', renderer='json', permission='Users', trans=True) -def delete(request): - id_ = request.matchdict['id'] - if id_ is None: - response = Response("User is Null") - response.status_int = 500 - return response - else: - response = Response("User deletion not implemented") - response.status_int = 500 - return response - - -@view_config(request_method='POST', route_name='v1_users_id', renderer='json', request_param='p', - permission='Authenticated', trans=True) -def update_password(request): - json = request.json_body - name = request.matchdict['id'] - old_password = json['oldPassword'] - new_password = json['newPassword'] - found, user = User.auth(name, old_password, request.dbsession) - if found: - user.password = new_password - transaction.commit() - return found - - -@view_config(request_method='GET', route_name='v1_users_id', renderer='json', permission='Authenticated') -def show_id(request): - id_ = request.matchdict['id'] - p = re.compile('^[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}$') - if p.match(id_): - item = request.dbsession.query(User).filter(User.id == uuid.UUID(id_)).one() - else: - item = request.dbsession.query(User).filter(User.name.ilike(id_)).first() - if item is None: - raise ValidationFailure('User name / id not found') - return user_info(item, request.dbsession, request.has_permission('Users')) - - -@view_config(request_method='GET', route_name='v1_users_new', renderer='json', permission='Authenticated') -def show_blank(request): - return user_info(None, request.dbsession, request.has_permission('Users')) - - -@view_config(request_method='GET', route_name='v1_users_list', renderer='json', permission='Users') -def show_list(request): - list_ = request.dbsession.query(User).order_by(User.name).all() - return [{ - 'id': item.id, - 'name': item.name, - 'lockedOut': item.locked_out, - 'roles': sorted(r.name for r in item.roles) - } for item in list_] - - -@view_config(request_method='GET', route_name='v1_users_list', renderer='json', request_param='names', - permission='Authenticated') -def show_name(request): - list_ = request.dbsession.query(User).filter(User.locked_out == False).order_by(User.name).all() - return [{'name': item.name} for item in list_] - - -def user_info(item, dbsession, has_users_permission): - roles = dbsession.query(Role).order_by(Role.name).all() if has_users_permission else [] - if item is None: - return { - 'name': '', - 'password': '', - 'lockedOut': False, - 'roles': [ - {'id': role.id, 'name': role.name, 'enabled': False} for role in roles - ] - } - if type(item) is uuid.UUID: - item = dbsession.query(User).filter(User.id == item.id).first() - return { - 'id': item.id, - 'name': item.name, - 'password': '', - 'lockedOut': item.locked_out, - 'roles': [ - {'id': role.id, 'name': role.name, 'enabled': True if role in item.roles else False} for role in roles - ] - } - - -def add_roles(user, roles, dbsession): - for role in roles: - id_ = uuid.UUID(role['id']) - ur = [r for r in user.roles if r.id == id_] - ur = None if len(ur) == 0 else ur[0] - if role['enabled'] and ur is None: - role_object = dbsession.query(Role).filter(Role.id == id_).one() - user.roles.append(role_object) - elif not role['enabled'] and ur: - user.roles.remove(ur) diff --git a/bookie/angular.json b/bookie/angular.json index 8d8ca78..c9234d8 100644 --- a/bookie/angular.json +++ b/bookie/angular.json @@ -13,6 +13,7 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "aot": true, "outputPath": "../barker/static", "index": "src/index.html", "main": "src/main.ts", @@ -50,6 +51,10 @@ "type": "initial", "maximumWarning": "2mb", "maximumError": "5mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" } ] } diff --git a/bookie/package.json b/bookie/package.json index 5f96c06..3835ecf 100644 --- a/bookie/package.json +++ b/bookie/package.json @@ -11,36 +11,36 @@ }, "private": true, "dependencies": { - "@angular/animations": "^8.0.0", - "@angular/cdk": "^8.0.1", - "@angular/common": "^8.0.0", - "@angular/compiler": "^8.0.0", - "@angular/core": "^8.0.0", - "@angular/flex-layout": "^8.0.0-beta.26", - "@angular/forms": "^8.0.0", - "@angular/material": "^8.0.1", - "@angular/material-moment-adapter": "^8.0.1", - "@angular/platform-browser": "^8.0.0", - "@angular/platform-browser-dynamic": "^8.0.0", - "@angular/router": "^8.0.0", - "angular2-hotkeys": "^2.1.4", + "@angular/animations": "^9.1.11", + "@angular/cdk": "^9.2.4", + "@angular/common": "^9.1.11", + "@angular/compiler": "^9.1.11", + "@angular/core": "^9.1.11", + "@angular/flex-layout": "^9.0.0-beta.31", + "@angular/forms": "^9.1.11", + "@angular/material": "^9.2.4", + "@angular/material-moment-adapter": "^9.2.4", + "@angular/platform-browser": "^9.1.11", + "@angular/platform-browser-dynamic": "^9.1.11", + "@angular/router": "^9.1.11", + "angular2-hotkeys": "^2.2.0", "core-js": "^3.1.1", - "hammerjs": "^2.0.8", "mathjs": "^5.10.3", "moment": "^2.24.0", - "rxjs": "^6.5.2", + "rxjs": "^6.5.5", "rxjs-tslint": "^0.1.5", - "zone.js": "~0.9.1" + "tslib": "^1.10.0", + "zone.js": "~0.10.2" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.800.0", - "@angular/cli": "^8.2.2", - "@angular/compiler-cli": "^8.0.0", - "@angular/language-service": "^8.0.0", + "@angular-devkit/build-angular": "~0.901.8", + "@angular/cli": "^9.1.8", + "@angular/compiler-cli": "^9.1.11", + "@angular/language-service": "^9.1.11", "@types/jasmine": "^3.3.0", "@types/jasminewd2": "^2.0.3", - "@types/node": "^12.0.2", - "codelyzer": "^5.0.1", + "@types/node": "^12.11.1", + "codelyzer": "^5.1.2", "jasmine-core": "^3.1.0", "jasmine-spec-reporter": "^4.2.1", "karma": "^4.1.0", @@ -52,6 +52,6 @@ "standard-version": "^6.0.1", "ts-node": "^8.1.0", "tslint": "^5.16.0", - "typescript": "3.4.5" + "typescript": "3.8.3" } } diff --git a/bookie/proxy.conf.json b/bookie/proxy.conf.json index e27caf9..c53f320 100644 --- a/bookie/proxy.conf.json +++ b/bookie/proxy.conf.json @@ -1,7 +1,27 @@ { - "/v1": { - "target": "http://localhost:6543", + "/api": { + "target": "http://localhost:9995", "secure": false, "logLevel": "debug" + }, + "/token": { + "target": "http://localhost:9995", + "secure": false, + "logLevel": "info" + }, + "/refresh": { + "target": "http://localhost:9995", + "secure": false, + "logLevel": "info" + }, + "/attendance-report": { + "target": "http://localhost:9995", + "secure": false, + "logLevel": "info" + }, + "/db-image": { + "target": "http://localhost:9995", + "secure": false, + "logLevel": "info" } } diff --git a/bookie/src/app/app.module.ts b/bookie/src/app/app.module.ts index 05144b0..c59f088 100644 --- a/bookie/src/app/app.module.ts +++ b/bookie/src/app/app.module.ts @@ -25,7 +25,7 @@ import { CoreModule } from './core/core.module'; import { ReactiveFormsModule } from '@angular/forms'; import { SharedModule } from './shared/shared.module'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { MatToolbarModule } from "@angular/material"; +import { MatToolbarModule } from "@angular/material/toolbar"; import { NavBarComponent } from './nav-bar/nav-bar.component'; registerLocaleData(enIN); diff --git a/bookie/src/app/auth/auth-guard.service.ts b/bookie/src/app/auth/auth-guard.service.ts index a9519ff..ddc84fb 100644 --- a/bookie/src/app/auth/auth-guard.service.ts +++ b/bookie/src/app/auth/auth-guard.service.ts @@ -1,39 +1,34 @@ import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; +import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; + import { AuthService } from './auth.service'; import { ToasterService } from '../core/toaster.service'; -import { User } from '../core/user'; -@Injectable({ - providedIn: 'root' -}) +@Injectable({providedIn: 'root'}) export class AuthGuard implements CanActivate { - - constructor(private auth: AuthService, private router: Router, private toaster: ToasterService) { + constructor( + private router: Router, + private authService: AuthService, + private toaster: ToasterService + ) { } - checkUser(permission: string, user: User, state: RouterStateSnapshot): boolean { - if (!user.isAuthenticated) { - this.router.navigate(['login'], {queryParams: {returnUrl: state.url}}); - this.toaster.show('Danger', 'User is not authenticated'); + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + const user = this.authService.user; + const permission = (route.data['permission'] === undefined) ? route.data['permission'] : route.data['permission'] + .replace(/ /g, '-') + .toLowerCase(); + if (!user) { + // not logged in so redirect to login page with the return url + this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}}); return false; } - - const hasPermission = this.auth.hasPermission(permission); - if (!hasPermission) { + if (permission !== undefined && user.perms.indexOf(permission) === -1) { this.toaster.show('Danger', 'You do not have the permission to access this area.'); + return false; } - return hasPermission; - } + // logged in so return true + return true; - canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean { - return this.auth.userObservable - .pipe( - map((value: User) => this.checkUser( - next.data['permission'], value, state - )) - ); } } diff --git a/bookie/src/app/auth/auth.service.ts b/bookie/src/app/auth/auth.service.ts index 7396383..7a1b9f4 100644 --- a/bookie/src/app/auth/auth.service.ts +++ b/bookie/src/app/auth/auth.service.ts @@ -1,64 +1,97 @@ import { Injectable } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Observable } from 'rxjs/internal/Observable'; -import { catchError, map, tap } from 'rxjs/operators'; -import { ErrorLoggerService } from '../core/error-logger.service'; +import { HttpClient } from '@angular/common/http'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + import { User } from '../core/user'; -import { merge, Subject } from 'rxjs'; +import { environment } from '../../environments/environment'; +const loginUrl = '/token'; +const refreshUrl = '/refresh'; +const JWT_USER = 'JWT_USER'; -const httpOptions = { - headers: new HttpHeaders({'Content-Type': 'application/json'}) -}; - -const loginUrl = '/v1/login'; -const logoutUrl = '/logout'; -const checkUrl = '/v1/auth'; - -@Injectable({ - providedIn: 'root' -}) +@Injectable({providedIn: 'root'}) export class AuthService { - private readonly userSubject: Subject; - private user: User; - public userObservable: Observable; - constructor(private http: HttpClient, private log: ErrorLoggerService) { - this.userSubject = new Subject(); - this.userObservable = merge(this.checkObserver(), this.userSubject).pipe( - tap(x => this.user = x) - ); + private currentUserSubject: BehaviorSubject; + public currentUser: Observable; + + constructor(private http: HttpClient) { + this.currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem(JWT_USER))); + this.currentUser = this.currentUserSubject.asObservable(); } - checkObserver(): Observable { - return >this.http.get(checkUrl, httpOptions); - } - - login(name: string, password: string, otp?: string, clientName?: string): Observable { - const data = {name: name, password: password}; - if (otp) { - data['otp'] = otp; + public get user(): User { + const val = this.currentUserSubject.value; + if (val == null) { + return val; } - - if (clientName) { - data['clientName'] = clientName; + const expired = Date.now() > val.exp * 1000; + if (expired) { + this.logout(); + return null; + } else { + return this.currentUserSubject.value; } - - return this.http.post(loginUrl, data, httpOptions) - .pipe( - tap((user: User) => this.userSubject.next(user)), - catchError(this.log.handleError('AuthService', 'login')) - ); } - logout(): Observable { - return >this.http.post(logoutUrl, {}, httpOptions) - .pipe( - tap((user: User) => this.userSubject.next(user)), - map(() => true) - ); + login(username: string, password: string, otp: string) { + const formData: FormData = new FormData(); + formData.append('username', username); + formData.append('password', password); + formData.append('otp', otp); + formData.append('grant_type', 'password'); + return this.http.post(loginUrl, formData) + .pipe(map(u => u.access_token)) + .pipe(map(u => this.parseJwt(u))) + .pipe(map(user => { + // store user details and jwt token in local storage to keep user logged in between page refreshes + localStorage.setItem(JWT_USER, JSON.stringify(user)); + this.currentUserSubject.next(user); + return user; + })); } - hasPermission(permission: string): boolean { - return this.user !== undefined && this.user.isAuthenticated && this.user.perms.indexOf(permission) !== -1; + parseJwt(token): User { + const base64Url = token.split('.')[1]; + const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); + const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + + const decoded = JSON.parse(jsonPayload); + return new User({ + id: decoded.userId, + name: decoded.sub, + lockedOut: decoded.lockedOut, + perms: decoded.scopes, + access_token: token, + exp: decoded.exp + }); + } + + needsRefreshing(): boolean { + return Date.now() > (this.user.exp - (environment.ACCESS_TOKEN_REFRESH_MINUTES * 60)) * 1000; + } + + expired(): boolean { + return Date.now() > this.user.exp * 1000; + } + + logout() { + // remove user from local storage to log user out + localStorage.removeItem(JWT_USER); + this.currentUserSubject.next(null); + } + + refreshToken() { + return this.http.post(refreshUrl, {}) + .pipe(map(u => u.access_token)) + .pipe(map(u => this.parseJwt(u))) + .pipe(map(user => { + // store user details and jwt token in local storage to keep user logged in between page refreshes + localStorage.setItem(JWT_USER, JSON.stringify(user)); + this.currentUserSubject.next(user); + return user; + })); } } diff --git a/bookie/src/app/auth/login/login.component.ts b/bookie/src/app/auth/login/login.component.ts index 09150c8..8e7664e 100644 --- a/bookie/src/app/auth/login/login.component.ts +++ b/bookie/src/app/auth/login/login.component.ts @@ -1,9 +1,9 @@ -import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; -import {AuthService} from '../auth.service'; -import {ActivatedRoute, Router} from '@angular/router'; -import {ToasterService} from '../../core/toaster.service'; -import {FormBuilder, FormGroup} from '@angular/forms'; -import {CookieService} from '../../shared/cookie.service'; +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { AuthService } from '../auth.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ToasterService } from '../../core/toaster.service'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { CookieService } from '../../shared/cookie.service'; @Component({ selector: 'app-login', @@ -15,7 +15,7 @@ export class LoginComponent implements OnInit, AfterViewInit { form: FormGroup; hide: boolean; showOtp: boolean; - clientID: string; + clientId: string; private returnUrl: string; constructor(private route: ActivatedRoute, @@ -34,8 +34,7 @@ export class LoginComponent implements OnInit, AfterViewInit { this.form = this.fb.group({ username: '', password: '', - otp: '', - clientName: '' + otp: '' }); } @@ -53,17 +52,20 @@ export class LoginComponent implements OnInit, AfterViewInit { const formModel = this.form.value; const username = formModel.username; const password = formModel.password; - this.auth.login(username, password).subscribe( - (result) => { - this.router.navigateByUrl(this.returnUrl); - }, - (error) => { - if (error.status === 403 && ['Unknown Client', 'OTP not supplied', 'OTP is wrong'].indexOf(error.error) !== -1) { - this.showOtp = true; - this.clientID = this.cs.getCookie('ClientID'); - } - this.toaster.show('Danger', error.error); - } - ); + const otp = formModel.otp; + this.auth.login(username, password, otp) + // .pipe(first()) + .subscribe( + data => { + this.router.navigate([this.returnUrl]); + }, + (error) => { + if (error.status === 401 && 'Client is not registered' === error.error.detail) { + this.showOtp = true; + this.clientId = this.cs.getCookie('client_id'); + } + this.toaster.show('Danger', error.error.details); + } + ) } } diff --git a/bookie/src/app/auth/logout/logout.component.ts b/bookie/src/app/auth/logout/logout.component.ts index 7be331b..b3e36ae 100644 --- a/bookie/src/app/auth/logout/logout.component.ts +++ b/bookie/src/app/auth/logout/logout.component.ts @@ -1,7 +1,7 @@ -import {Component, OnInit} from '@angular/core'; -import {Router} from '@angular/router'; -import {AuthService} from '../auth.service'; -import {ToasterService} from '../../core/toaster.service'; +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { AuthService } from '../auth.service'; +import { ToasterService } from '../../core/toaster.service'; @Component({ selector: 'app-logout', @@ -9,17 +9,11 @@ import {ToasterService} from '../../core/toaster.service'; }) export class LogoutComponent implements OnInit { - constructor(private auth: AuthService, private router: Router, private toaster: ToasterService) { + constructor(private auth: AuthService) { } ngOnInit() { - this.auth.logout().subscribe( - (result) => { - this.toaster.show('Success', 'Logged Out'); - this.router.navigateByUrl('/'); - }, - (error) => this.toaster.show('Danger', error.error) - ); + this.auth.logout(); } } diff --git a/bookie/src/app/cashier-report/cashier-report.module.ts b/bookie/src/app/cashier-report/cashier-report.module.ts index 34ab001..96aad87 100644 --- a/bookie/src/app/cashier-report/cashier-report.module.ts +++ b/bookie/src/app/cashier-report/cashier-report.module.ts @@ -21,7 +21,7 @@ import { CashierReportComponent } from './cashier-report.component'; import { MomentDateAdapter } from '@angular/material-moment-adapter'; import { A11yModule } from '@angular/cdk/a11y'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { MatSelectModule } from '@angular/material'; +import { MatSelectModule } from '@angular/material/select'; export const MY_FORMATS = { parse: { diff --git a/bookie/src/app/core/core.module.ts b/bookie/src/app/core/core.module.ts index 8256fd2..a98df4b 100644 --- a/bookie/src/app/core/core.module.ts +++ b/bookie/src/app/core/core.module.ts @@ -1,12 +1,13 @@ -import {NgModule} from '@angular/core'; -import {CommonModule} from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { MatToolbarModule } from '@angular/material/toolbar'; -import {RouterModule} from '@angular/router'; -import {HTTP_INTERCEPTORS} from '@angular/common/http'; -import {HttpAuthInterceptor} from './http-auth-interceptor'; +import { RouterModule } from '@angular/router'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { ErrorInterceptor } from './http-auth-interceptor'; +import { JwtInterceptor } from './jwt.interceptor'; @NgModule({ imports: [ @@ -19,11 +20,10 @@ import {HttpAuthInterceptor} from './http-auth-interceptor'; ], declarations: [ ], - providers: [[{ - provide: HTTP_INTERCEPTORS, - useClass: HttpAuthInterceptor, - multi: true - }]] + providers: [ + {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, + {provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true}, + ] }) export class CoreModule { } diff --git a/bookie/src/app/core/http-auth-interceptor.ts b/bookie/src/app/core/http-auth-interceptor.ts index 0f0c108..d05f341 100644 --- a/bookie/src/app/core/http-auth-interceptor.ts +++ b/bookie/src/app/core/http-auth-interceptor.ts @@ -1,44 +1,51 @@ -import {Injectable} from '@angular/core'; -import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; - -import {Observable, throwError} from 'rxjs'; -import {catchError} from 'rxjs/operators'; -import {ToasterService} from './toaster.service'; -import {Router} from '@angular/router'; -import {ConfirmDialogComponent} from '../shared/confirm-dialog/confirm-dialog.component'; +import { Observable, throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { Injectable } from '@angular/core'; +import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; +import { Router } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; +import { AuthService } from '../auth/auth.service'; +import { ToasterService } from './toaster.service'; +import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component'; @Injectable() -export class HttpAuthInterceptor implements HttpInterceptor { - - constructor(private router: Router, private dialog: MatDialog, private toaster: ToasterService) { +export class ErrorInterceptor implements HttpInterceptor { + constructor(private authService: AuthService, private router: Router, private dialog: MatDialog, private toaster: ToasterService) { } - intercept(req: HttpRequest, next: HttpHandler): - Observable> { - return next.handle(req) - .pipe( - catchError((error: any) => { - if (error.status === 401) { - this.toaster.show('Danger', 'User has been logged out'); - const dialogRef = this.dialog.open(ConfirmDialogComponent, { - width: '250px', - data: { - title: 'Logged out!', - content: 'You have been logged out.\n' + - 'You can press Cancel to stay on page and login in another tab to resume here,' + - ' or you can press Ok to navigate to the login page.' - } - }); - dialogRef.afterClosed().subscribe((result: boolean) => { - if (result) { - this.router.navigate(['login']); - } - }); - } - return throwError(error); - } - ) - ); + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe(catchError(err => { + // We don't want to refresh token for some requests like login or refresh token itself + // So we verify url and we throw an error if it's the case + if (request.url.includes('/refresh') || request.url.includes('/token')) { + // We do another check to see if refresh token failed + // In this case we want to logout user and to redirect it to login page + if (request.url.includes('/refresh')) { + this.authService.logout(); + } + return throwError(err); + } + // If error status is different than 401 we want to skip refresh token + // So we check that and throw the error if it's the case + if (err.status !== 401) { + const error = err.error.message || err.error.detail || err.statusText; + return throwError(error); + } + // auto logout if 401 response returned from api + this.authService.logout(); + this.toaster.show('Danger', 'User has been logged out'); + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '250px', + data: { + title: 'Logged out!', + content: 'You have been logged out.\nYou can press Cancel to stay on page and login in another tab to resume here, or you can press Ok to navigate to the login page.' + } + }); + dialogRef.afterClosed().subscribe((result: boolean) => { + if (result) { + this.router.navigate(['login']); + } + }); + })); } } diff --git a/bookie/src/app/core/jwt.interceptor.ts b/bookie/src/app/core/jwt.interceptor.ts new file mode 100644 index 0000000..4c4bfef --- /dev/null +++ b/bookie/src/app/core/jwt.interceptor.ts @@ -0,0 +1,35 @@ +import {Injectable} from '@angular/core'; +import {HttpRequest, HttpHandler, HttpEvent, HttpInterceptor} from '@angular/common/http'; +import {Observable} from 'rxjs'; + +import {AuthService} from '../auth/auth.service'; + +@Injectable() +export class JwtInterceptor implements HttpInterceptor { + private isRefreshing = false; + + constructor(private authService: AuthService) { + } + + intercept(request: HttpRequest, next: HttpHandler): Observable> { + // add authorization header with jwt token if available + + // We use this line to debug token refreshing + // console.log("intercepting:\nisRefreshing: ", this.isRefreshing, "\n user: ", this.authService.user,"\n needsRefreshing: ", this.authService.needsRefreshing()); + if (!this.isRefreshing && this.authService.user && this.authService.needsRefreshing()) { + this.isRefreshing = true; + this.authService.refreshToken().subscribe( x=> this.isRefreshing = false); + } + const currentUser = this.authService.user; + if (currentUser?.access_token) { + request = request.clone({ + setHeaders: { + Authorization: `Bearer ${currentUser.access_token}` + } + }); + } + + + return next.handle(request); + } +} diff --git a/bookie/src/app/core/user.ts b/bookie/src/app/core/user.ts index 44d3bb2..c9bc46f 100644 --- a/bookie/src/app/core/user.ts +++ b/bookie/src/app/core/user.ts @@ -3,16 +3,18 @@ export class User { name: string; password: string; lockedOut: boolean; - roles: UserRole[]; + roles?: UserGroup[]; perms: string[]; isAuthenticated: boolean; + access_token?: string; + exp?: number; public constructor(init?: Partial) { Object.assign(this, init); } } -export class UserRole { +export class UserGroup { id: string; name: string; enabled: boolean; diff --git a/bookie/src/app/home/home.component.html b/bookie/src/app/home/home.component.html index d8f5a03..1e081f6 100644 --- a/bookie/src/app/home/home.component.html +++ b/bookie/src/app/home/home.component.html @@ -1,68 +1,68 @@
- +

Guest Book

- +

Sales

- +

Cashier Report

- +

Sale Report

- +

Tax Report

- +

Product Sale Report

- +

Bill Settlement Report

- +

Beer Consumption Report

- +

Discount Report

- +

Tables

- +

Sections

- +

Menu Categories

- +

Sale Categories

- +

Products

- +

Modifier Categories

- +

Modifiers

- +

Taxes

- +

Devices

- +

Section Printers

- +

Printers

- +

Roles

- +

Users

diff --git a/bookie/src/app/menu-category/menu-category-detail/menu-category-detail.component.ts b/bookie/src/app/menu-category/menu-category-detail/menu-category-detail.component.ts index 469940c..ccf7a0f 100644 --- a/bookie/src/app/menu-category/menu-category-detail/menu-category-detail.component.ts +++ b/bookie/src/app/menu-category/menu-category-detail/menu-category-detail.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { MenuCategoryService } from '../menu-category.service'; import { MenuCategory } from '../../core/menu-category'; diff --git a/bookie/src/app/menu-category/menu-category-list/menu-category-list.component.ts b/bookie/src/app/menu-category/menu-category-list/menu-category-list.component.ts index b0607f0..3fc95a5 100644 --- a/bookie/src/app/menu-category/menu-category-list/menu-category-list.component.ts +++ b/bookie/src/app/menu-category/menu-category-list/menu-category-list.component.ts @@ -3,7 +3,7 @@ import { MenuCategoryListDatasource } from './menu-category-list-datasource'; import { MenuCategory } from '../../core/menu-category'; import { ActivatedRoute, Router } from '@angular/router'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; -import { MatTable } from '@angular/material'; +import { MatTable } from '@angular/material/table'; import { ToasterService } from '../../core/toaster.service'; import { MenuCategoryService } from '../menu-category.service'; import { BehaviorSubject } from 'rxjs'; diff --git a/bookie/src/app/menu-category/menu-category.service.ts b/bookie/src/app/menu-category/menu-category.service.ts index 3c15e52..b2b3262 100644 --- a/bookie/src/app/menu-category/menu-category.service.ts +++ b/bookie/src/app/menu-category/menu-category.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {MenuCategory} from '../core/menu-category'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { MenuCategory } from '../core/menu-category'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/menu-categories'; +const url = '/api/menu-categories'; const serviceName = 'MenuCategoryService'; @Injectable({ @@ -19,7 +19,7 @@ export class MenuCategoryService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? url : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,15 +27,14 @@ export class MenuCategoryService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } save(menuCategory: MenuCategory): Observable { - return >this.http.post(`${url}/new`, menuCategory, httpOptions) + return >this.http.post(url, menuCategory, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); diff --git a/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.ts b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.ts index f067a54..075ace3 100644 --- a/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.ts +++ b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.ts @@ -8,7 +8,7 @@ import {MatDialog} from '@angular/material/dialog'; import {FormBuilder, FormGroup} from '@angular/forms'; import {MenuCategory} from '../../core/menu-category'; import {NestedTreeControl} from '@angular/cdk/tree'; -import {MatTreeNestedDataSource} from '@angular/material'; +import { MatTreeNestedDataSource } from '@angular/material/tree'; import {Product} from '../../core/product'; @Component({ diff --git a/bookie/src/app/modifier-categories/modifier-category.service.ts b/bookie/src/app/modifier-categories/modifier-category.service.ts index 1fc38ca..eae2a65 100644 --- a/bookie/src/app/modifier-categories/modifier-category.service.ts +++ b/bookie/src/app/modifier-categories/modifier-category.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {ModifierCategory} from '../core/modifier-category'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { ModifierCategory } from '../core/modifier-category'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/modifier-categories'; +const url = '/api/modifier-categories'; const serviceName = 'ModifierCategoryService'; @Injectable({ @@ -19,7 +19,7 @@ export class ModifierCategoryService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? url : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,23 +27,22 @@ export class ModifierCategoryService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } - listIsActiveOfProduct(id: string): Observable { - const options = {params: new HttpParams().set('p', id).set('a', '')}; - return >this.http.get(url, options) + listForProduct(id: string): Observable { + return >this.http.get(`${url}/for-product/${id}`) .pipe( catchError(this.log.handleError(serviceName, 'listIsActiveOfProduct')) ); } + save(modifierCategory: ModifierCategory): Observable { - return >this.http.post(`${url}/new`, modifierCategory, httpOptions) + return >this.http.post(url, modifierCategory, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); diff --git a/bookie/src/app/modifiers/modifier-list/modifier-list.component.ts b/bookie/src/app/modifiers/modifier-list/modifier-list.component.ts index 5767f7d..2eec228 100644 --- a/bookie/src/app/modifiers/modifier-list/modifier-list.component.ts +++ b/bookie/src/app/modifiers/modifier-list/modifier-list.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ModifierListDataSource } from './modifier-list-datasource'; -import { MatTable } from '@angular/material'; +import { MatTable } from '@angular/material/table'; import { Modifier } from '../../core/modifier'; import { BehaviorSubject } from 'rxjs'; import {ModifierCategory} from '../../core/modifier-category'; diff --git a/bookie/src/app/nav-bar/nav-bar.component.html b/bookie/src/app/nav-bar/nav-bar.component.html index c3a1ab8..54a6374 100644 --- a/bookie/src/app/nav-bar/nav-bar.component.html +++ b/bookie/src/app/nav-bar/nav-bar.component.html @@ -4,11 +4,11 @@ Point of Sale - - diff --git a/bookie/src/app/nav-bar/nav-bar.component.ts b/bookie/src/app/nav-bar/nav-bar.component.ts index 740b956..7ca8f1c 100644 --- a/bookie/src/app/nav-bar/nav-bar.component.ts +++ b/bookie/src/app/nav-bar/nav-bar.component.ts @@ -1,24 +1,20 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from "rxjs"; -import { map, share } from "rxjs/operators"; -import { AuthService } from "../auth/auth.service"; +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { AuthService } from '../auth/auth.service'; @Component({ selector: 'app-nav-bar', templateUrl: './nav-bar.component.html', styleUrls: ['./nav-bar.component.css'] }) -export class NavBarComponent implements OnInit { - public user: Observable; +export class NavBarComponent { - constructor(public auth: AuthService) { + constructor(private router: Router, public auth: AuthService) { } - ngOnInit() { - this.user = this.auth.userObservable.pipe( - map (x => x.isAuthenticated ? x.name : null), - share() - ); - } + logout() { + this.auth.logout(); + this.router.navigate(['/']); + } } diff --git a/bookie/src/app/product/product-list/product-list-datasource.ts b/bookie/src/app/product/product-list/product-list-datasource.ts index 81e75a1..5d5c479 100644 --- a/bookie/src/app/product/product-list/product-list-datasource.ts +++ b/bookie/src/app/product/product-list/product-list-datasource.ts @@ -40,9 +40,13 @@ export class ProductListDataSource extends DataSource { private getFilteredData(data: Product[]): Product[] { const filter = (this.filterValue === undefined) ? '' : this.filterValue; + if (filter === '') { + return data; + } else { return data.filter(x => { - return x.menuCategory.id === filter || filter === ''; + return x.menuCategory.id === filter; } ); + } } } diff --git a/bookie/src/app/product/product-list/product-list.component.ts b/bookie/src/app/product/product-list/product-list.component.ts index aea5fc5..8c117b0 100644 --- a/bookie/src/app/product/product-list/product-list.component.ts +++ b/bookie/src/app/product/product-list/product-list.component.ts @@ -3,7 +3,6 @@ import { ActivatedRoute, Router } from '@angular/router'; import { FormBuilder, FormGroup } from '@angular/forms'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { ProductListDataSource } from './product-list-datasource'; -import { MatTable } from '@angular/material'; import { Product } from '../../core/product'; import { ToCsvService } from '../../shared/to-csv.service'; import { ToasterService } from '../../core/toaster.service'; @@ -17,7 +16,6 @@ import { BehaviorSubject } from 'rxjs'; styleUrls: ['./product-list.component.css'] }) export class ProductListComponent implements OnInit { - @ViewChild('table', { static: true }) table: MatTable; dataSource: ProductListDataSource; filter: BehaviorSubject; form: FormGroup; @@ -30,7 +28,6 @@ export class ProductListComponent implements OnInit { constructor( private route: ActivatedRoute, private fb: FormBuilder, - private router: Router, private toaster: ToasterService, private toCsv: ToCsvService, private ser: ProductService @@ -50,20 +47,24 @@ export class ProductListComponent implements OnInit { } ngOnInit() { + this.dataSource = new ProductListDataSource(this.filter, this.data); this.route.data .subscribe((data: { list: Product[], menuCategories: MenuCategory[] }) => { - this.data.next(data.list); - this.menuCategories = data.menuCategories; + this.loadData(data.list, data.menuCategories); }); - this.dataSource = new ProductListDataSource(this.filter, this.data); + } + + loadData(list: Product[], menuCategories: MenuCategory[]) { + this.menuCategories = menuCategories; + this.data.next(list); } updateSortOrder() { this.ser.updateSortOrder(this.dataSource.viewData) .subscribe( - (result) => { + (result: Product[]) => { this.toaster.show('Success', ''); - this.router.navigateByUrl('/products'); + this.loadData(result, this.menuCategories); }, (error) => { this.toaster.show('Danger', error.error); diff --git a/bookie/src/app/product/product.service.ts b/bookie/src/app/product/product.service.ts index 60f7f8a..cef5e54 100644 --- a/bookie/src/app/product/product.service.ts +++ b/bookie/src/app/product/product.service.ts @@ -9,7 +9,7 @@ const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/products'; +const url = '/api/products'; const serviceName = 'ProductService'; @Injectable({providedIn: 'root'}) @@ -19,7 +19,7 @@ export class ProductService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? `${url}` : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,23 +27,22 @@ export class ProductService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } listIsActiveOfCategory(id: string): Observable { - const options = {params: new HttpParams().set('mc', id).set('a', '')}; - return >this.http.get(url, options) + const options = {params: new HttpParams().set('mc', id).set('a', 'true')}; + return >this.http.get(`${url}/query`, options) .pipe( catchError(this.log.handleError(serviceName, 'listIsActiveOfCategory')) ); } save(product: Product): Observable { - return >this.http.post(`${url}/new`, product, httpOptions) + return >this.http.post(`${url}`, product, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); @@ -56,8 +55,8 @@ export class ProductService { ); } - updateSortOrder(list: Product[]): Observable { - return >this.http.post(url, list, httpOptions) + updateSortOrder(list: Product[]): Observable { + return >this.http.post(`${url}/list`, list, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'updateSortOrder')) ); @@ -78,17 +77,9 @@ export class ProductService { ); } - autocomplete(term: string): Observable { - const options = {params: new HttpParams().set('t', term)}; - return >this.http.get(url, options) - .pipe( - catchError(this.log.handleError(serviceName, 'autocomplete')) - ); - } - balance(id: string, date: string): Observable { - const options = {params: new HttpParams().set('b', 'true').set('d', date)}; - return >this.http.get(`${url}/${id}`, options) + const options = {params: new HttpParams().set('d', date)}; + return >this.http.get(`${url}/balance`, options) .pipe( catchError(this.log.handleError(serviceName, 'balance')) ); diff --git a/bookie/src/app/roles/role.service.ts b/bookie/src/app/roles/role.service.ts index cd5a3ee..b5b1232 100644 --- a/bookie/src/app/roles/role.service.ts +++ b/bookie/src/app/roles/role.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {Role} from './role'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { Role } from './role'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/roles'; +const url = '/api/roles'; const serviceName = 'RoleService'; @Injectable({ @@ -19,7 +19,7 @@ export class RoleService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? `${url}` : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,23 +27,14 @@ export class RoleService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) - .pipe( - catchError(this.log.handleError(serviceName, 'list')) - ); - } - - listOfNames(): Observable { - const options = {params: new HttpParams().set('n', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } save(role: Role): Observable { - return >this.http.post(`${url}/new`, role, httpOptions) + return >this.http.post(`${url}`, role, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); diff --git a/bookie/src/app/sale-category/sale-category-detail/sale-category-detail.component.ts b/bookie/src/app/sale-category/sale-category-detail/sale-category-detail.component.ts index a1a53b6..417d2c5 100644 --- a/bookie/src/app/sale-category/sale-category-detail/sale-category-detail.component.ts +++ b/bookie/src/app/sale-category/sale-category-detail/sale-category-detail.component.ts @@ -1,7 +1,7 @@ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { SaleCategoryService } from '../sale-category.service'; import { SaleCategory } from '../../core/sale-category'; diff --git a/bookie/src/app/sale-category/sale-category-list/sale-category-list.component.ts b/bookie/src/app/sale-category/sale-category-list/sale-category-list.component.ts index 0c5ef88..e7c0e09 100644 --- a/bookie/src/app/sale-category/sale-category-list/sale-category-list.component.ts +++ b/bookie/src/app/sale-category/sale-category-list/sale-category-list.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { SaleCategoryListDatasource } from './sale-category-list-datasource'; import { SaleCategory } from '../../core/sale-category'; import { ActivatedRoute, Router } from '@angular/router'; -import { MatTable } from '@angular/material'; +import { MatTable } from '@angular/material/table'; import { ToasterService } from '../../core/toaster.service'; import { SaleCategoryService } from '../sale-category.service'; import { BehaviorSubject } from 'rxjs'; diff --git a/bookie/src/app/sale-category/sale-category.service.ts b/bookie/src/app/sale-category/sale-category.service.ts index c4a89f5..760b00a 100644 --- a/bookie/src/app/sale-category/sale-category.service.ts +++ b/bookie/src/app/sale-category/sale-category.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {SaleCategory} from '../core/sale-category'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { SaleCategory } from '../core/sale-category'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/sale-categories'; +const url = '/api/sale-categories'; const serviceName = 'SaleCategoryService'; @Injectable({ @@ -19,7 +19,7 @@ export class SaleCategoryService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? url : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,23 +27,21 @@ export class SaleCategoryService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } listForDiscount(): Observable<{name: string, discount: number}[]> { - const options = {params: new HttpParams().set('d', '')}; - return >this.http.get<{name: string, discount: number}[]>(url, options) + return >this.http.get<{name: string, discount: number}[]>(`${url}/for-discount`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } save(saleCategory: SaleCategory): Observable { - return >this.http.post(`${url}/new`, saleCategory, httpOptions) + return >this.http.post(url, saleCategory, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); @@ -56,13 +54,6 @@ export class SaleCategoryService { ); } - updateSortOrder(list: SaleCategory[]): Observable { - return >this.http.post(url, list, httpOptions) - .pipe( - catchError(this.log.handleError(serviceName, 'updateSortOrder')) - ); - } - saveOrUpdate(saleCategory: SaleCategory): Observable { if (!saleCategory.id) { return this.save(saleCategory); diff --git a/bookie/src/app/sales/bill-type/bill-type.component.ts b/bookie/src/app/sales/bill-type/bill-type.component.ts index 4bea60b..770129a 100644 --- a/bookie/src/app/sales/bill-type/bill-type.component.ts +++ b/bookie/src/app/sales/bill-type/bill-type.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { MatDialogRef } from '@angular/material'; +import { MatDialogRef } from '@angular/material/dialog'; import { PrintType } from '../bills/bill'; @Component({ diff --git a/bookie/src/app/sales/bill.service.ts b/bookie/src/app/sales/bill.service.ts index 1284cf1..fe54550 100644 --- a/bookie/src/app/sales/bill.service.ts +++ b/bookie/src/app/sales/bill.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { BehaviorSubject } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; import * as math from 'mathjs'; @@ -92,7 +92,7 @@ export class BillService { modifiers: [] }; this.data.push(item); - this.modifierCategoryService.listIsActiveOfProduct(product.id).subscribe(result => { + this.modifierCategoryService.listForProduct(product.id).subscribe(result => { if (result.reduce((a: any, c: ModifierCategory) => { return a + c.minimum; }, 0)) { @@ -111,7 +111,7 @@ export class BillService { top: '10vh' }, data: { - list: this.modifierCategoryService.listIsActiveOfProduct(item.productId), + list: this.modifierCategoryService.listForProduct(item.productId), selected: item.modifiers } }); diff --git a/bookie/src/app/sales/bills/bills.component.ts b/bookie/src/app/sales/bills/bills.component.ts index b19ce0a..c50443b 100644 --- a/bookie/src/app/sales/bills/bills.component.ts +++ b/bookie/src/app/sales/bills/bills.component.ts @@ -4,7 +4,7 @@ import { Bill, Kot } from './bill'; import { BillsDataSource } from './bills-datasource'; import { BillService } from '../bill.service'; import { QuantityComponent } from '../quantity/quantity.component'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { Table } from '../../core/table'; import { Observable, throwError } from 'rxjs'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; @@ -133,7 +133,7 @@ export class BillsComponent implements OnInit { } moveKot(kot: Kot) { - const canMergeTables = this.auth.hasPermission('Merge Tables'); + const canMergeTables = (this.auth.user.perms.indexOf('merge-tables') === -1); this.dialog.open(TablesDialogComponent, { // width: '750px', data: { diff --git a/bookie/src/app/sales/discount/discount.component.ts b/bookie/src/app/sales/discount/discount.component.ts index 223ac92..4e5ffc7 100644 --- a/bookie/src/app/sales/discount/discount.component.ts +++ b/bookie/src/app/sales/discount/discount.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Observable } from 'rxjs'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { DiscountDataSource } from './discount-datasource'; diff --git a/bookie/src/app/sales/home/sales-home.component.ts b/bookie/src/app/sales/home/sales-home.component.ts index 9421b3e..a23663c 100644 --- a/bookie/src/app/sales/home/sales-home.component.ts +++ b/bookie/src/app/sales/home/sales-home.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { map, switchMap, tap } from 'rxjs/operators'; import { Observable, of as observableOf, throwError } from 'rxjs'; import { BillService } from '../bill.service'; @@ -39,7 +39,7 @@ export class SalesHomeComponent implements OnInit { } printKotAllowed(): boolean { - if (!this.auth.hasPermission('Print Kot')) { + if (this.auth.user.perms.indexOf('print-kot') === -1) { return false; } if (!this.bs.bill.id) { @@ -69,7 +69,7 @@ export class SalesHomeComponent implements OnInit { } discountAllowed(): boolean { - return this.auth.hasPermission('Discount'); + return this.auth.user.perms.indexOf('discount') === -1; } showDiscount(): Observable { @@ -120,13 +120,13 @@ export class SalesHomeComponent implements OnInit { } printBillAllowed(): boolean { - if (!this.auth.hasPermission('Print Bill')) { + if (this.auth.user.perms.indexOf('print-bill') === -1) { return false; } if (!this.bs.bill.id) { return true; } - if (this.bs.bill.voucherType !== PrintType.Kot && !this.auth.hasPermission('Edit Printed Bill')) { + if (this.bs.bill.voucherType !== PrintType.Kot && this.auth.user.perms.indexOf('edit-printed-bill') === -1) { return false; } if (this.bs.bill.isVoid) { @@ -169,7 +169,7 @@ export class SalesHomeComponent implements OnInit { } receivePaymentAllowed(): boolean { - if (!this.auth.hasPermission('Settle Bill')) { + if (this.auth.user.perms.indexOf('settle-bill') === -1) { return false; } if (!this.bs.bill.id) { @@ -251,7 +251,8 @@ export class SalesHomeComponent implements OnInit { } moveTableAllowed(): boolean { - if (!this.auth.hasPermission('Move Table') && !this.auth.hasPermission('Merge Tables')) { + // TODO: Check if this condition should be "and" or "or" + if (this.auth.user.perms.indexOf('move-table') === -1 && this.auth.user.perms.indexOf('merge-tables') === -1) { return false; } if (!this.bs.bill.id) { @@ -264,7 +265,7 @@ export class SalesHomeComponent implements OnInit { if (!this.moveTableAllowed()) { return; } - const canMergeTables = this.auth.hasPermission('Merge Tables'); + const canMergeTables = (this.auth.user.perms.indexOf('merge-tables') === -1); this.dialog.open(TablesDialogComponent, { // width: '750px', data: { @@ -299,7 +300,7 @@ export class SalesHomeComponent implements OnInit { } voidBillAllowed(): boolean { - if (!this.auth.hasPermission('Void Bill')) { + if (this.auth.user.perms.indexOf('void-bill') === -1) { return false; } if (!this.bs.bill.id) { @@ -351,7 +352,7 @@ export class SalesHomeComponent implements OnInit { } splitBillAllowed(): boolean { - if (!this.auth.hasPermission('Split Bill')) { + if (this.auth.user.perms.indexOf('split-bill') === -1) { return false; } if (!this.bs.bill.id) { diff --git a/bookie/src/app/sales/modifiers/modifiers.component.ts b/bookie/src/app/sales/modifiers/modifiers.component.ts index 82ff727..c8a0db6 100644 --- a/bookie/src/app/sales/modifiers/modifiers.component.ts +++ b/bookie/src/app/sales/modifiers/modifiers.component.ts @@ -1,7 +1,7 @@ import { Component, Inject } from '@angular/core'; import { ModifierCategory } from '../../core/modifier-category'; import { Modifier } from '../../core/modifier'; -import { MAT_DIALOG_DATA } from '@angular/material'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import { Observable } from 'rxjs'; @Component({ diff --git a/bookie/src/app/sales/pax/pax.component.ts b/bookie/src/app/sales/pax/pax.component.ts index a2aef13..18c723e 100644 --- a/bookie/src/app/sales/pax/pax.component.ts +++ b/bookie/src/app/sales/pax/pax.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ diff --git a/bookie/src/app/sales/quantity/quantity.component.ts b/bookie/src/app/sales/quantity/quantity.component.ts index dabae71..dbb2f33 100644 --- a/bookie/src/app/sales/quantity/quantity.component.ts +++ b/bookie/src/app/sales/quantity/quantity.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ diff --git a/bookie/src/app/sales/reason/reason.component.ts b/bookie/src/app/sales/reason/reason.component.ts index b48a7c6..a9d9ff8 100644 --- a/bookie/src/app/sales/reason/reason.component.ts +++ b/bookie/src/app/sales/reason/reason.component.ts @@ -1,5 +1,5 @@ import { Component, ElementRef, Inject, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ReasonDatasource } from './reason-datasource'; import { FormBuilder, FormGroup } from "@angular/forms"; diff --git a/bookie/src/app/sales/receive-payment/receive-payment.component.ts b/bookie/src/app/sales/receive-payment/receive-payment.component.ts index 438d359..61aa55b 100644 --- a/bookie/src/app/sales/receive-payment/receive-payment.component.ts +++ b/bookie/src/app/sales/receive-payment/receive-payment.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; import { distinctUntilChanged } from 'rxjs/operators'; import { ReceivePaymentDatasource } from './receive-payment-datasource'; diff --git a/bookie/src/app/sales/sales.module.ts b/bookie/src/app/sales/sales.module.ts index 2c33da4..982bc88 100644 --- a/bookie/src/app/sales/sales.module.ts +++ b/bookie/src/app/sales/sales.module.ts @@ -11,7 +11,8 @@ import { MatDialogModule } from '@angular/material/dialog'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; -import { MatRippleModule, MatTooltipModule } from '@angular/material'; +import { MatRippleModule } from '@angular/material/core'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { FlexLayoutModule } from '@angular/flex-layout'; @@ -72,16 +73,6 @@ import { PaxComponent } from "./pax/pax.component"; MatTooltipModule, SharedModule, SalesRoutingModule - ], - entryComponents: [ - BillTypeComponent, - DiscountComponent, - ModifiersComponent, - PaxComponent, - QuantityComponent, - ReceivePaymentComponent, - TablesDialogComponent, - ReasonComponent ] }) export class SalesModule { } diff --git a/bookie/src/app/sales/tables-dialog/tables-dialog.component.ts b/bookie/src/app/sales/tables-dialog/tables-dialog.component.ts index 35c2697..85b88c5 100644 --- a/bookie/src/app/sales/tables-dialog/tables-dialog.component.ts +++ b/bookie/src/app/sales/tables-dialog/tables-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Observable } from 'rxjs'; import { Table } from '../../core/table'; diff --git a/bookie/src/app/shared/shared.module.ts b/bookie/src/app/shared/shared.module.ts index 2a6b0aa..1db13b4 100644 --- a/bookie/src/app/shared/shared.module.ts +++ b/bookie/src/app/shared/shared.module.ts @@ -21,10 +21,6 @@ import {ImageDialogComponent} from './image-dialog/image-dialog.component'; ClearPipe, LocalTimePipe ], - entryComponents: [ - ConfirmDialogComponent, - ImageDialogComponent - ], exports: [ AccountingPipe, ClearPipe, diff --git a/bookie/src/app/tables/table-detail/table-detail.component.ts b/bookie/src/app/tables/table-detail/table-detail.component.ts index 3055c9d..9496a27 100644 --- a/bookie/src/app/tables/table-detail/table-detail.component.ts +++ b/bookie/src/app/tables/table-detail/table-detail.component.ts @@ -6,7 +6,7 @@ import {ActivatedRoute, Router} from '@angular/router'; import {ToasterService} from '../../core/toaster.service'; import {FormBuilder, FormGroup} from '@angular/forms'; import {ConfirmDialogComponent} from '../../shared/confirm-dialog/confirm-dialog.component'; -import {MatDialog} from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import {Section} from '../../core/section'; @Component({ diff --git a/bookie/src/app/tables/table-list/table-list.component.ts b/bookie/src/app/tables/table-list/table-list.component.ts index adf425d..9c57c0c 100644 --- a/bookie/src/app/tables/table-list/table-list.component.ts +++ b/bookie/src/app/tables/table-list/table-list.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { TableListDataSource } from './table-list-datasource'; import { Table } from '../../core/table'; import { ActivatedRoute, Router } from '@angular/router'; -import { MatTable } from '@angular/material'; +import { MatTable } from '@angular/material/table'; import { MenuCategory } from '../../core/menu-category'; import { BehaviorSubject } from 'rxjs'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; diff --git a/bookie/src/app/taxes/tax.service.ts b/bookie/src/app/taxes/tax.service.ts index e57294c..dcd9548 100644 --- a/bookie/src/app/taxes/tax.service.ts +++ b/bookie/src/app/taxes/tax.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {Tax} from '../core/tax'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { Tax } from '../core/tax'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/taxes'; +const url = '/api/taxes'; const serviceName = 'TaxService'; @Injectable({ @@ -19,7 +19,7 @@ export class TaxService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? url : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,15 +27,14 @@ export class TaxService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } save(tax: Tax): Observable { - return >this.http.post(`${url}/new`, tax, httpOptions) + return >this.http.post(url, tax, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); diff --git a/bookie/src/app/users/user-list/user-list.component.html b/bookie/src/app/users/user-list/user-list.component.html index 069e92f..d2a9d9a 100644 --- a/bookie/src/app/users/user-list/user-list.component.html +++ b/bookie/src/app/users/user-list/user-list.component.html @@ -12,7 +12,7 @@ Name - {{row.name}} + {{row.name}} diff --git a/bookie/src/app/users/user.service.ts b/bookie/src/app/users/user.service.ts index b983b0b..9c7e8cc 100644 --- a/bookie/src/app/users/user.service.ts +++ b/bookie/src/app/users/user.service.ts @@ -1,14 +1,14 @@ -import {Injectable} from '@angular/core'; -import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; -import {ErrorLoggerService} from '../core/error-logger.service'; -import {catchError} from 'rxjs/operators'; -import {Observable} from 'rxjs/internal/Observable'; -import {User} from '../core/user'; +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { ErrorLoggerService } from '../core/error-logger.service'; +import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs/internal/Observable'; +import { User } from '../core/user'; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) }; -const url = '/v1/users'; +const url = '/api/users'; const serviceName = 'UserService'; @Injectable({ @@ -19,7 +19,7 @@ export class UserService { } get(id: string): Observable { - const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + const getUrl: string = (id === null) ? `${url}` : `${url}/${id}`; return >this.http.get(getUrl) .pipe( catchError(this.log.handleError(serviceName, `get id=${id}`)) @@ -27,23 +27,21 @@ export class UserService { } list(): Observable { - const options = {params: new HttpParams().set('l', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/list`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } listOfNames(): Observable { - const options = {params: new HttpParams().set('n', '')}; - return >this.http.get(url, options) + return >this.http.get(`${url}/active`) .pipe( catchError(this.log.handleError(serviceName, 'list')) ); } save(user: User): Observable { - return >this.http.post(`${url}/new`, user, httpOptions) + return >this.http.post(`${url}`, user, httpOptions) .pipe( catchError(this.log.handleError(serviceName, 'save')) ); diff --git a/bookie/src/environments/environment.prod.ts b/bookie/src/environments/environment.prod.ts index 3612073..8860a3d 100644 --- a/bookie/src/environments/environment.prod.ts +++ b/bookie/src/environments/environment.prod.ts @@ -1,3 +1,4 @@ export const environment = { - production: true + production: true, + ACCESS_TOKEN_REFRESH_MINUTES: 10 // refresh token 10 minutes before expiry }; diff --git a/bookie/src/environments/environment.ts b/bookie/src/environments/environment.ts index 7b4f817..0798195 100644 --- a/bookie/src/environments/environment.ts +++ b/bookie/src/environments/environment.ts @@ -3,7 +3,8 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + ACCESS_TOKEN_REFRESH_MINUTES: 10 // refresh token 10 minutes before expiry }; /* diff --git a/bookie/src/main.ts b/bookie/src/main.ts index 3b2b7d0..e76caee 100644 --- a/bookie/src/main.ts +++ b/bookie/src/main.ts @@ -1,4 +1,4 @@ -import 'hammerjs'; + import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; diff --git a/bookie/src/tsconfig.app.json b/bookie/src/tsconfig.app.json index 190fd30..f3a1b80 100644 --- a/bookie/src/tsconfig.app.json +++ b/bookie/src/tsconfig.app.json @@ -4,8 +4,11 @@ "outDir": "../out-tsc/app", "types": [] }, - "exclude": [ - "test.ts", - "**/*.spec.ts" + "files": [ + "main.ts", + "polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" ] } diff --git a/requirements.txt b/requirements.txt index 7540447..fe22da0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,15 @@ -pyramid -waitress -transaction -zope.sqlalchemy -SQLAlchemy -psycopg2 - +setuptools +wheel +uvicorn +fastapi +python-jose[cryptography] +passlib[bcrypt] +psycopg2-binary +sqlalchemy +python-multipart +pyjwt +alembic +itsdangerous +python-dotenv +pydantic[dotenv] +starlette