diff --git a/barker/models/__init__.py b/barker/models/__init__.py index 313e9dd..27c542d 100644 --- a/barker/models/__init__.py +++ b/barker/models/__init__.py @@ -27,7 +27,7 @@ from .master import ( PrintLocation, Product, MenuCategory, - MenuCategoryModifier, + ModifierCategory, SaleCategory, SettleOption, Tax diff --git a/barker/models/auth.py b/barker/models/auth.py index c72c669..6f262f1 100644 --- a/barker/models/auth.py +++ b/barker/models/auth.py @@ -57,15 +57,17 @@ class Client(Base): user_roles = Table( 'user_roles', Base.metadata, Column('id', GUID(), primary_key=True, default=uuid.uuid4), - Column('user_id', GUID(), ForeignKey('users.id')), - Column('role_id', GUID(), ForeignKey('roles.id')) + Column('user_id', GUID(), ForeignKey('users.id'), nullable=False), + Column('role_id', GUID(), 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')), - Column('role_id', GUID(), ForeignKey('roles.id')) + Column('permission_id', GUID(), ForeignKey('permissions.id'), nullable=False), + Column('role_id', GUID(), ForeignKey('roles.id'), nullable=False), + UniqueConstraint('permission_id', 'role_id') ) diff --git a/barker/models/master.py b/barker/models/master.py index b784047..15212a0 100644 --- a/barker/models/master.py +++ b/barker/models/master.py @@ -10,7 +10,7 @@ from sqlalchemy import ( Integer, case, JSON, -) + Table) from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship from .meta import Base @@ -200,6 +200,34 @@ class Product(Base): return True, "" +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), + UniqueConstraint('product_id', 'modifier_categories_id') +) + + +class ModifierCategory(Base): + __tablename__ = "modifier_categories" + + id = Column("id", GUID(), 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) + sort_order = Column("sort_order", Numeric, nullable=False) + + products = relationship("Product", secondary=modifier_categories_products, backref="modifier_categories") + + def __init__(self, name=None, minimum=None, maximum=None, sort_order=0, id=None): + self.id = id + self.name = name + self.minimum = minimum + self.maximum = maximum + self.sort_order = sort_order + + class Modifier(Base): __tablename__ = "modifiers" @@ -207,38 +235,20 @@ class Modifier(Base): 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) + modifier_category_id = Column( + "modifier_category_id", GUID(), ForeignKey("modifier_categories.id"), nullable=False + ) - def __init__(self, name=None, show_in_bill=None, price=None, id=None): + modifier_category = relationship("ModifierCategory", backref="modifiers") + + def __init__(self, name=None, show_in_bill=None, price=None, modifier_category_id=None, id=None): self.id = id self.name = name self.show_in_bill = show_in_bill + self.modifier_category_id = modifier_category_id self.price = price -class MenuCategoryModifier(Base): - __tablename__ = "menu_category_modifiers" - - id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) - menu_category_id = Column( - "menu_cateory_id", GUID(), ForeignKey("menu_categories.id") - ) - modifier_id = Column( - "modifier_id", GUID(), ForeignKey("modifiers.id"), nullable=False - ) - show_automatically = Column("show_automatically", Boolean, nullable=False) - - menu_category = relationship("MenuCategory", backref="modifiers") - modifier = relationship("Modifier", backref="menu_categories") - - def __init__( - self, menu_category_id=None, modifier_id=None, show_automatically=None, id=None - ): - self.id = id - self.menu_category_id = menu_category_id - self.modifier_id = modifier_id - self.show_automatically = show_automatically - - class DbSetting(Base): __tablename__ = "settings" diff --git a/barker/routes.py b/barker/routes.py index ef63b77..c57d0cf 100644 --- a/barker/routes.py +++ b/barker/routes.py @@ -63,6 +63,14 @@ def includeme(config): config.add_route("v1_sale_categories_list", "/v1/sale-categories") config.add_route("v1_sale_category_types_list", "/v1/sale-category-types") + config.add_route("modifier_categories_new", "/modifier-categories/new") + config.add_route("modifier_categories_id", "/modifier-categories/{id}") + config.add_route("modifier_categories_list", "/modifier-categories") + config.add_route("v1_modifier_categories_new", "/v1/modifier-categories/new") + config.add_route("v1_modifier_categories_id", "/v1/modifier-categories/{id}") + config.add_route("v1_modifier_categories_list", "/v1/modifier-categories") + config.add_route("v1_modifier_category_types_list", "/v1/modifier-category-types") + config.add_route("v1_bills_new", "/v1/bills/new") config.add_route("v1_bills_id", "/v1/bills/{id}") diff --git a/barker/scripts/initializedb.py b/barker/scripts/initializedb.py index 3a6d8fe..93b432c 100644 --- a/barker/scripts/initializedb.py +++ b/barker/scripts/initializedb.py @@ -32,7 +32,8 @@ from barker.models import ( Printer, Product, MenuCategory, - MenuCategoryModifier, + ModifierCategory, + SaleCategory, Reprint, Role, role_permissions, diff --git a/barker/views/modifier.py b/barker/views/modifier.py index 763bb14..d1ef96d 100644 --- a/barker/views/modifier.py +++ b/barker/views/modifier.py @@ -5,10 +5,10 @@ import transaction from pyramid.view import view_config from sqlalchemy import or_ -from barker.models import Modifier, MenuCategoryModifier +from barker.models import Modifier, ModifierCategory -@view_config(request_method='PUT', route_name='modifier', renderer='json', permission='Modifiers', trans=True) +@view_config(request_method='POST', route_name='modifier', renderer='json', permission='Modifiers', trans=True) def save(request): json = request.json_body item = Modifier(json['Name'], json['ShowInBill'], json['Price']) @@ -19,7 +19,7 @@ def save(request): return modifier_info(item) -@view_config(request_method='POST', route_name='modifier_id', renderer='json', permission='Modifiers', trans=True) +@view_config(request_method='PUT', route_name='modifier_id', renderer='json', permission='Modifiers', trans=True) def update(request): json = request.json_body item = request.dbsession.query(Modifier).filter(Modifier.id == uuid.UUID(request.matchdict['id'])).first() diff --git a/barker/views/modifier_category.py b/barker/views/modifier_category.py new file mode 100644 index 0000000..8d1bb41 --- /dev/null +++ b/barker/views/modifier_category.py @@ -0,0 +1,260 @@ +import uuid + +import transaction + +from pyramid.view import view_config +from sqlalchemy import or_ +from sqlalchemy.orm import joinedload, Load + +from barker.models import ModifierCategory, Product +from barker.models.validation_exception import ValidationError +from barker.views import product + + +@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") + item = ModifierCategory(name, minimum, maximum) + 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") + 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() + ) + modifier_categories = [] + for item in list_: + modifier_categories.append( + { + "id": item.id, + "name": item.name, + "minimum": item.minimum, + "maximum": item.maximum, + "products": [p.name for p in item.products], + } + ) + return modifier_categories + + +@view_config( + request_method="GET", + route_name="v1_modifier_categories_list", + renderer="json", + request_param="pg", + permission="Authenticated", +) +def show_for_pg(request): + menu_category_id = uuid.UUID(request.GET["pg"]) + pgm_list = ( + request.dbsession.query(MenuCategoryModifier) + .filter( + or_( + MenuCategoryModifier.menu_category == None, + MenuCategoryModifier.menu_category_id == menu_category_id, + ) + ) + .all() + ) + + pg_modifiers = [] + for item in pgm_list: + pg_modifiers.append( + { + "ModifierID": item.modifier_id, + "Name": item.modifier.name, + "ShowInBill": item.modifier.show_in_bill, + "Price": item.modifier.price, + } + ) + return pg_modifiers + + +def modifier_category_info(item, dbsession): + from barker.models import MenuCategory + + menu_categories = ( + dbsession.query(MenuCategory) + .options(joinedload(MenuCategory.products, innerjoin=True)) + .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, + "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, + "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/role.py b/barker/views/role.py index 6b38d09..ad041c8 100644 --- a/barker/views/role.py +++ b/barker/views/role.py @@ -13,9 +13,7 @@ def save(request): request.dbsession.add(item) add_permissions(item, request.json_body['permissions'], request.dbsession) transaction.commit() - item = request.dbsession.query(Role).filter(Role.id == item.id).first() - permissions = request.dbsession.query(Permission).order_by(Permission.name).all() - return role_info(item, permissions) + return role_info(item.id, request.dbsession) @view_config(request_method='PUT', route_name='v1_roles_id', renderer='json', permission='Users', trans=True) @@ -25,9 +23,7 @@ def update(request): item.name = request.json_body['name'] add_permissions(item, request.json_body['permissions'], request.dbsession) transaction.commit() - item = request.dbsession.query(Role).filter(Role.id == item.id).first() - permissions = request.dbsession.query(Permission).order_by(Permission.name).all() - return role_info(item, permissions) + return role_info(item.id, request.dbsession) def add_permissions(role, permissions, dbsession): @@ -58,15 +54,12 @@ def delete(request): @view_config(request_method='GET', route_name='v1_roles_id', renderer='json', permission='Authenticated') def show_id(request): id_ = uuid.UUID(request.matchdict['id']) - item = request.dbsession.query(Role).filter(Role.id == id_).first() - permissions = request.dbsession.query(Permission).order_by(Permission.name).all() - return role_info(item, permissions) + return role_info(id_, request.dbsession) @view_config(request_method='GET', route_name='v1_roles_new', renderer='json', permission='Authenticated') def show_blank(request): - permissions = request.dbsession.query(Permission).order_by(Permission.name).all() - return role_info(None, permissions) + return role_info(None, request.dbsession) @view_config(request_method='GET', route_name='v1_roles_list', renderer='json', permission='Authenticated') @@ -77,16 +70,18 @@ def show_list(request): ] -def role_info(item, permissions): - if item is not None: - 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 permissions] - } - else: +def role_info(item, dbsession): + permissions = dbsession.query(Permission).order_by(Permission.name).all() + if item is None: return { 'name': '', '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() + 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 permissions] + } diff --git a/bookie/src/app/app-routing.module.ts b/bookie/src/app/app-routing.module.ts index c72766c..e74afdc 100644 --- a/bookie/src/app/app-routing.module.ts +++ b/bookie/src/app/app-routing.module.ts @@ -13,6 +13,10 @@ const routes: Routes = [ path: 'guest-book', loadChildren: () => import('./guest-book/guest-book.module').then(mod => mod.GuestBookModule) }, + { + path: 'modifier-categories', + loadChildren: () => import('./modifier-categories/modifier-categories.module').then(mod => mod.ModifierCategoriesModule) + }, { path: 'printers', loadChildren: () => import('./printers/printers.module').then(mod => mod.PrintersModule) diff --git a/bookie/src/app/core/menu-category.ts b/bookie/src/app/core/menu-category.ts index 838eae3..27735f1 100644 --- a/bookie/src/app/core/menu-category.ts +++ b/bookie/src/app/core/menu-category.ts @@ -1,3 +1,5 @@ +import {Product} from "./product"; + export class MenuCategory { id: string; name: string; @@ -6,4 +8,6 @@ export class MenuCategory { isActive: boolean; isFixture: boolean; sortOrder: number; + products: Product[]; + enabled?: boolean; } diff --git a/bookie/src/app/core/product.ts b/bookie/src/app/core/product.ts index 898fe55..97821db 100644 --- a/bookie/src/app/core/product.ts +++ b/bookie/src/app/core/product.ts @@ -14,4 +14,6 @@ export class Product { quantity: number; isActive: boolean; sortOrder: number; + + enabled?: boolean; } diff --git a/bookie/src/app/guest-book/guest-book-list/guest-book-list.component.html b/bookie/src/app/guest-book/guest-book-list/guest-book-list.component.html index bc48781..fad5c27 100644 --- a/bookie/src/app/guest-book/guest-book-list/guest-book-list.component.html +++ b/bookie/src/app/guest-book/guest-book-list/guest-book-list.component.html @@ -19,7 +19,7 @@ - + S. No {{row.serial}} @@ -31,13 +31,13 @@ {{row.name}} - + Phone {{row.phone}} - + Pax {{row.pax}} diff --git a/bookie/src/app/home/home.component.html b/bookie/src/app/home/home.component.html index 3dfed08..43ad38b 100644 --- a/bookie/src/app/home/home.component.html +++ b/bookie/src/app/home/home.component.html @@ -19,6 +19,9 @@ Products + + Modifier Categories + Taxes diff --git a/bookie/src/app/modifier-categories/modifier-categories-routing.module.spec.ts b/bookie/src/app/modifier-categories/modifier-categories-routing.module.spec.ts new file mode 100644 index 0000000..8a9c6c3 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-categories-routing.module.spec.ts @@ -0,0 +1,13 @@ +import { ModifierCategoriesRoutingModule } from './modifier-categories-routing.module'; + +describe('ModifierCategoriesRoutingModule', () => { + let rolesRoutingModule: ModifierCategoriesRoutingModule; + + beforeEach(() => { + rolesRoutingModule = new ModifierCategoriesRoutingModule(); + }); + + it('should create an instance', () => { + expect(rolesRoutingModule).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/modifier-categories/modifier-categories-routing.module.ts b/bookie/src/app/modifier-categories/modifier-categories-routing.module.ts new file mode 100644 index 0000000..56f7b84 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-categories-routing.module.ts @@ -0,0 +1,61 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule, Routes } from '@angular/router'; +import { ModifierCategoryListResolver } from './modifier-category-list-resolver.service'; +import { ModifierCategoryResolver } from './modifier-category-resolver.service'; +import { ModifierCategoryListComponent } from './modifier-category-list/modifier-category-list.component'; +import { ModifierCategoryDetailComponent } from './modifier-category-detail/modifier-category-detail.component'; +import { AuthGuard } from '../auth/auth-guard.service'; + +const roleRoutes: Routes = [ + { + path: '', + component: ModifierCategoryListComponent, + canActivate: [AuthGuard], + data: { + permission: 'Users' + }, + resolve: { + list: ModifierCategoryListResolver + } + }, + { + path: 'new', + component: ModifierCategoryDetailComponent, + canActivate: [AuthGuard], + data: { + permission: 'Users' + }, + resolve: { + item: ModifierCategoryResolver, + } + }, + { + path: ':id', + component: ModifierCategoryDetailComponent, + canActivate: [AuthGuard], + data: { + permission: 'Users' + }, + resolve: { + item: ModifierCategoryResolver + } + } +]; + +@NgModule({ + imports: [ + CommonModule, + RouterModule.forChild(roleRoutes) + + ], + exports: [ + RouterModule + ], + providers: [ + ModifierCategoryListResolver, + ModifierCategoryResolver + ] +}) +export class ModifierCategoriesRoutingModule { +} diff --git a/bookie/src/app/modifier-categories/modifier-categories.module.spec.ts b/bookie/src/app/modifier-categories/modifier-categories.module.spec.ts new file mode 100644 index 0000000..7b34a0b --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-categories.module.spec.ts @@ -0,0 +1,13 @@ +import { ModifierCategoriesModule } from './modifier-categories.module'; + +describe('ModifierCategoriesModule', () => { + let rolesModule: ModifierCategoriesModule; + + beforeEach(() => { + rolesModule = new ModifierCategoriesModule(); + }); + + it('should create an instance', () => { + expect(rolesModule).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/modifier-categories/modifier-categories.module.ts b/bookie/src/app/modifier-categories/modifier-categories.module.ts new file mode 100644 index 0000000..a6edf77 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-categories.module.ts @@ -0,0 +1,43 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {ModifierCategoryListComponent} from './modifier-category-list/modifier-category-list.component'; +import {ModifierCategoryDetailComponent} from './modifier-category-detail/modifier-category-detail.component'; +import {ModifierCategoriesRoutingModule} from './modifier-categories-routing.module'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatTableModule } from '@angular/material/table'; +import {CdkTableModule} from '@angular/cdk/table'; +import {ReactiveFormsModule} from '@angular/forms'; +import {SharedModule} from '../shared/shared.module'; +import {FlexLayoutModule} from '@angular/flex-layout'; + +@NgModule({ + imports: [ + CommonModule, + CdkTableModule, + FlexLayoutModule, + MatButtonModule, + MatCardModule, + MatCheckboxModule, + MatDividerModule, + MatIconModule, + MatInputModule, + MatProgressSpinnerModule, + MatTableModule, + ReactiveFormsModule, + SharedModule, + ModifierCategoriesRoutingModule + ], + declarations: [ + ModifierCategoryListComponent, + ModifierCategoryDetailComponent + ] +}) +export class ModifierCategoriesModule { +} diff --git a/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.css b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.css new file mode 100644 index 0000000..82c7afd --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.css @@ -0,0 +1,3 @@ +.example-card { + max-width: 400px; +} diff --git a/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.html b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.html new file mode 100644 index 0000000..528385e --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.html @@ -0,0 +1,46 @@ +
+ + + ModifierCategory + + +
+
+ + Name + + +
+
+ + Minimum + + + + Maximum + + +
+ +
+
+ {{mc.name}} +
+
+ {{p.name}} +
+
+
+
+
+
+ + + + +
+
diff --git a/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.spec.ts b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.spec.ts new file mode 100644 index 0000000..4a1267d --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.spec.ts @@ -0,0 +1,25 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {ModifierCategoryDetailComponent} from './modifier-category-detail.component'; + +describe('ModifierCategoryDetailComponent', () => { + let component: ModifierCategoryDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ModifierCategoryDetailComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ModifierCategoryDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000..0361d72 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-detail/modifier-category-detail.component.ts @@ -0,0 +1,146 @@ +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ModifierCategoryService } from '../modifier-category.service'; +import { ModifierCategory } from '../modifier-category'; +import { ToasterService } from '../../core/toaster.service'; +import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; +import {Product} from "../../core/product"; + +@Component({ + selector: 'app-role-detail', + templateUrl: './modifier-category-detail.component.html', + styleUrls: ['./modifier-category-detail.component.css'] +}) +export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit { + @ViewChild('nameElement', { static: true }) nameElement: ElementRef; + form: FormGroup; + item: ModifierCategory; + + constructor( + private route: ActivatedRoute, + private router: Router, + private fb: FormBuilder, + private toaster: ToasterService, + private dialog: MatDialog, + private ser: ModifierCategoryService + ) { + this.createForm(); + } + + createForm() { + this.form = this.fb.group({ + name: '', + minimum: '', + maximum: '', + menuCategories: this.fb.array([]) + }); + // this.setMenuCategories(); + } + + setMenuCategories(){ + this.form.setControl('menuCategories', this.fb.array( + this.item.menuCategories.map( + x => this.fb.group({ + menuCategory: x.enabled, + products: new FormArray( + x.products.map( + y => this.fb.group({ + product: y.enabled + }) + ) + ) + }) + ) + )); + } + + setProducts(x: any[]){ + return ; + } + + ngOnInit() { + this.route.data + .subscribe((data: { item: ModifierCategory }) => { + this.showItem(data.item); + }); + } + + showItem(item: ModifierCategory) { + this.item = item; + console.log(item); + this.form.patchValue({ + name: this.item.name || '', + minimum: '' + this.item.minimum, + maximum: '' + this.item.maximum + }); + this.setMenuCategories(); + // this.form.setControl('menuCategories', this.fb.array( + // this.item.menuCategories.map( + // x => this.fb.group({ + // product: x.enabled + // }) + // ) + // )); + } + + ngAfterViewInit() { + setTimeout(() => { + this.nameElement.nativeElement.focus(); + }, 0); + } + + save() { + this.ser.saveOrUpdate(this.getItem()) + .subscribe( + (result) => { + this.toaster.show('Success', ''); + this.router.navigateByUrl('/modifier-categories'); + }, + (error) => { + this.toaster.show('Danger', error.error); + } + ); + } + + delete() { + this.ser.delete(this.item.id) + .subscribe( + (result) => { + this.toaster.show('Success', ''); + this.router.navigateByUrl('/modifier-categories'); + }, + (error) => { + this.toaster.show('Danger', error.error); + } + ); + } + + confirmDelete(): void { + const dialogRef = this.dialog.open(ConfirmDialogComponent, { + width: '250px', + data: {title: 'Delete Modifier Category?', content: 'Are you sure? This cannot be undone.'} + }); + + dialogRef.afterClosed().subscribe((result: boolean) => { + if (result) { + this.delete(); + } + }); + } + + getItem(): ModifierCategory { + const formModel = this.form.value; + this.item.name = formModel.name; + this.item.minimum = +formModel.minimum; + this.item.maximum = +formModel.maximum; + const mc = this.form.get('menuCategories') as FormArray; + this.item.menuCategories.forEach((item, i) => { + item.products.forEach((prod, j) => { + prod.enabled = mc.value[i].products[j].product; + }); + }); + return this.item; + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.spec.ts b/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.spec.ts new file mode 100644 index 0000000..68c8c79 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.spec.ts @@ -0,0 +1,15 @@ +import {inject, TestBed} from '@angular/core/testing'; + +import {ModifierCategoryListResolver} from './modifier-category-list-resolver.service'; + +describe('ModifierCategoryListResolver', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ModifierCategoryListResolver] + }); + }); + + it('should be created', inject([ModifierCategoryListResolver], (service: ModifierCategoryListResolver) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.ts b/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.ts new file mode 100644 index 0000000..a7f43bd --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list-resolver.service.ts @@ -0,0 +1,18 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router'; +import {ModifierCategory} from './modifier-category'; +import {Observable} from 'rxjs/internal/Observable'; +import {ModifierCategoryService} from './modifier-category.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ModifierCategoryListResolver implements Resolve { + + constructor(private ser: ModifierCategoryService, private router: Router) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.ser.list(); + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list-datasource.ts b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list-datasource.ts new file mode 100644 index 0000000..63e7be8 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list-datasource.ts @@ -0,0 +1,17 @@ +import { DataSource } from '@angular/cdk/collections'; +import { Observable, of as observableOf } from 'rxjs'; +import { ModifierCategory } from '../modifier-category'; + +export class ModifierCategoryListDatasource extends DataSource { + + constructor(public data: ModifierCategory[]) { + super(); + } + + connect(): Observable { + return observableOf(this.data); + } + + disconnect() { + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.css b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.html b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.html new file mode 100644 index 0000000..de054a8 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.html @@ -0,0 +1,44 @@ + + + Modifier Categories + + add_box + Add + + + + + + + + Name + {{row.name}} + + + + + Minimum + {{row.minimum}} + + + + + Maximum + {{row.maximum}} + + + + + Products + +
    +
  • {{product}}
  • +
+
+
+ + + +
+
+
diff --git a/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.spec.ts b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.spec.ts new file mode 100644 index 0000000..c21bedb --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.spec.ts @@ -0,0 +1,23 @@ +import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing'; + +import {ModifierCategoryListComponent} from './modifier-category-list.component'; + +describe('ModifierCategoryListComponent', () => { + let component: ModifierCategoryListComponent; + let fixture: ComponentFixture; + + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + declarations: [ModifierCategoryListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ModifierCategoryListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should compile', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.ts b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.ts new file mode 100644 index 0000000..c30ab6c --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-list/modifier-category-list.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; +import { ModifierCategoryListDatasource } from './modifier-category-list-datasource'; +import { ModifierCategory } from '../modifier-category'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'app-modifier-category-list', + templateUrl: './modifier-category-list.component.html', + styleUrls: ['./modifier-category-list.component.css'] +}) +export class ModifierCategoryListComponent implements OnInit { + dataSource: ModifierCategoryListDatasource; + list: ModifierCategory[]; + /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ + displayedColumns = ['name', 'minimum', 'maximum', 'products']; + + constructor(private route: ActivatedRoute) { + } + + ngOnInit() { + this.route.data + .subscribe((data: { list: ModifierCategory[] }) => { + this.list = data.list; + }); + this.dataSource = new ModifierCategoryListDatasource(this.list); + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category-resolver.service.spec.ts b/bookie/src/app/modifier-categories/modifier-category-resolver.service.spec.ts new file mode 100644 index 0000000..d90f74b --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-resolver.service.spec.ts @@ -0,0 +1,15 @@ +import {inject, TestBed} from '@angular/core/testing'; + +import {ModifierCategoryResolver} from './modifier-category-resolver.service'; + +describe('ModifierCategoryResolver', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ModifierCategoryResolver] + }); + }); + + it('should be created', inject([ModifierCategoryResolver], (service: ModifierCategoryResolver) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/bookie/src/app/modifier-categories/modifier-category-resolver.service.ts b/bookie/src/app/modifier-categories/modifier-category-resolver.service.ts new file mode 100644 index 0000000..203b791 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category-resolver.service.ts @@ -0,0 +1,19 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot} from '@angular/router'; +import {ModifierCategory} from './modifier-category'; +import {Observable} from 'rxjs/internal/Observable'; +import {ModifierCategoryService} from './modifier-category.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ModifierCategoryResolver implements Resolve { + + constructor(private ser: ModifierCategoryService, private router: Router) { + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const id = route.paramMap.get('id'); + return this.ser.get(id); + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category.service.spec.ts b/bookie/src/app/modifier-categories/modifier-category.service.spec.ts new file mode 100644 index 0000000..ef02eeb --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category.service.spec.ts @@ -0,0 +1,15 @@ +import {inject, TestBed} from '@angular/core/testing'; + +import {ModifierCategoryService} from './modifier-category.service'; + +describe('ModifierCategoryService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ModifierCategoryService] + }); + }); + + it('should be created', inject([ModifierCategoryService], (service: ModifierCategoryService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/bookie/src/app/modifier-categories/modifier-category.service.ts b/bookie/src/app/modifier-categories/modifier-category.service.ts new file mode 100644 index 0000000..a780244 --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category.service.ts @@ -0,0 +1,73 @@ +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 './modifier-category'; + +const httpOptions = { + headers: new HttpHeaders({'Content-Type': 'application/json'}) +}; +const url = '/v1/modifier-categories'; +const serviceName = 'ModifierCategoryService'; + +@Injectable({ + providedIn: 'root' +}) +export class ModifierCategoryService { + constructor(private http: HttpClient, private log: ErrorLoggerService) { + } + + get(id: string): Observable { + const getUrl: string = (id === null) ? `${url}/new` : `${url}/${id}`; + return >this.http.get(getUrl) + .pipe( + catchError(this.log.handleError(serviceName, `get id=${id}`)) + ); + } + + 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) + .pipe( + catchError(this.log.handleError(serviceName, 'list')) + ); + } + + save(role: ModifierCategory): Observable { + return >this.http.post(`${url}/new`, role, httpOptions) + .pipe( + catchError(this.log.handleError(serviceName, 'save')) + ); + } + + update(role: ModifierCategory): Observable { + return >this.http.put(`${url}/${role.id}`, role, httpOptions) + .pipe( + catchError(this.log.handleError(serviceName, 'update')) + ); + } + + saveOrUpdate(role: ModifierCategory): Observable { + if (!role.id) { + return this.save(role); + } else { + return this.update(role); + } + } + + delete(id: string): Observable { + return >this.http.delete(`${url}/${id}`, httpOptions) + .pipe( + catchError(this.log.handleError(serviceName, 'delete')) + ); + } +} diff --git a/bookie/src/app/modifier-categories/modifier-category.ts b/bookie/src/app/modifier-categories/modifier-category.ts new file mode 100644 index 0000000..2bb960f --- /dev/null +++ b/bookie/src/app/modifier-categories/modifier-category.ts @@ -0,0 +1,9 @@ +import {MenuCategory} from "../core/menu-category"; + +export class ModifierCategory { + id: string; + name: string; + minimum: number; + maximum: number; + menuCategories: MenuCategory[]; +} diff --git a/bookie/src/app/product/product-detail/product-detail.component.ts b/bookie/src/app/product/product-detail/product-detail.component.ts index a5f7d67..c169e25 100644 --- a/bookie/src/app/product/product-detail/product-detail.component.ts +++ b/bookie/src/app/product/product-detail/product-detail.component.ts @@ -52,7 +52,6 @@ export class ProductDetailComponent implements OnInit, AfterViewInit { .subscribe((data: { item: Product, menuCategories: MenuCategory[], saleCategories: SaleCategory[] }) => { this.menuCategories = data.menuCategories; this.saleCategories = data.saleCategories; - console.log(this.saleCategories); this.showItem(data.item); }); }