Modifier Category Working
This commit is contained in:
1 parent
e4072d0872
commit
4f0346551a
24 files changed
+231
-215
No files matched your search
@@ -14,6 +14,8 @@ from ..models.menu_category import MenuCategory
|
|||||||
from ..models.modifier_category import ModifierCategory
|
from ..models.modifier_category import ModifierCategory
|
||||||
from ..models.product import Product
|
from ..models.product import Product
|
||||||
from ..models.product_version import ProductVersion
|
from ..models.product_version import ProductVersion
|
||||||
|
from ..models.sku_version import SkuVersion
|
||||||
|
from ..models.stock_keeping_unit import StockKeepingUnit
|
||||||
from ..schemas import modifier_category as schemas
|
from ..schemas import modifier_category as schemas
|
||||||
from ..schemas.menu_category import MenuCategoryLink
|
from ..schemas.menu_category import MenuCategoryLink
|
||||||
from ..schemas.modifier_category_for_product import ModifierCategoryForProduct, ModifierLink
|
from ..schemas.modifier_category_for_product import ModifierCategoryForProduct, ModifierLink
|
||||||
@@ -41,7 +43,7 @@ def save(
|
|||||||
is_active=data.is_active,
|
is_active=data.is_active,
|
||||||
)
|
)
|
||||||
db.add(item)
|
db.add(item)
|
||||||
add_products(item, data.menu_categories, db)
|
add_skus(item, data.menu_categories, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
return modifier_category_info(item, date_, db=db)
|
return modifier_category_info(item, date_, db=db)
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
@@ -65,7 +67,7 @@ def update_route(
|
|||||||
item.minimum = data.minimum
|
item.minimum = data.minimum
|
||||||
item.maximum = None if data.maximum == 0 else data.maximum
|
item.maximum = None if data.maximum == 0 else data.maximum
|
||||||
item.is_active = data.is_active
|
item.is_active = data.is_active
|
||||||
add_products(item, data.menu_categories, db)
|
add_skus(item, data.menu_categories, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
return modifier_category_info(item, date_, db=db)
|
return modifier_category_info(item, date_, db=db)
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
@@ -109,7 +111,7 @@ def show_list(
|
|||||||
) -> list[schemas.ModifierCategory]:
|
) -> list[schemas.ModifierCategory]:
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
product_version_onclause = and_(
|
product_version_onclause = and_(
|
||||||
ProductVersion.menu_category_id == MenuCategory.id,
|
ProductVersion.product_id == Product.id,
|
||||||
or_(
|
or_(
|
||||||
ProductVersion.valid_from == None, # noqa: E711
|
ProductVersion.valid_from == None, # noqa: E711
|
||||||
ProductVersion.valid_from <= date_,
|
ProductVersion.valid_from <= date_,
|
||||||
@@ -119,6 +121,22 @@ def show_list(
|
|||||||
ProductVersion.valid_till >= date_,
|
ProductVersion.valid_till >= date_,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
sku_version_onclause = and_(
|
||||||
|
SkuVersion.sku_id == StockKeepingUnit.id,
|
||||||
|
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711
|
||||||
|
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711
|
||||||
|
)
|
||||||
|
sku_version_menu_category_onclause = and_(
|
||||||
|
SkuVersion.menu_category_id == MenuCategory.id,
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_from == None, # noqa: E711
|
||||||
|
SkuVersion.valid_from <= date_,
|
||||||
|
),
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_till == None, # noqa: E711
|
||||||
|
SkuVersion.valid_till >= date_,
|
||||||
|
),
|
||||||
|
)
|
||||||
list_ = (
|
list_ = (
|
||||||
db.execute(select(ModifierCategory).order_by(ModifierCategory.sort_order).order_by(ModifierCategory.name))
|
db.execute(select(ModifierCategory).order_by(ModifierCategory.sort_order).order_by(ModifierCategory.name))
|
||||||
.scalars()
|
.scalars()
|
||||||
@@ -127,9 +145,17 @@ def show_list(
|
|||||||
menu_categories = (
|
menu_categories = (
|
||||||
db.execute(
|
db.execute(
|
||||||
select(MenuCategory)
|
select(MenuCategory)
|
||||||
|
.join(SkuVersion, onclause=sku_version_menu_category_onclause)
|
||||||
|
.join(StockKeepingUnit, onclause=sku_version_onclause)
|
||||||
|
.join(StockKeepingUnit.product)
|
||||||
.join(ProductVersion, onclause=product_version_onclause)
|
.join(ProductVersion, onclause=product_version_onclause)
|
||||||
.order_by(MenuCategory.sort_order, ProductVersion.sort_order, ProductVersion.name)
|
.order_by(MenuCategory.sort_order, StockKeepingUnit.sort_order, ProductVersion.name)
|
||||||
.options(contains_eager(MenuCategory.products))
|
.options(
|
||||||
|
contains_eager(MenuCategory.skus)
|
||||||
|
.contains_eager(SkuVersion.sku)
|
||||||
|
.contains_eager(StockKeepingUnit.product)
|
||||||
|
.contains_eager(Product.versions)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.unique()
|
.unique()
|
||||||
.scalars()
|
.scalars()
|
||||||
@@ -149,13 +175,17 @@ def show_list(
|
|||||||
schemas.MenuCategoryLink(
|
schemas.MenuCategoryLink(
|
||||||
id_=mc.id,
|
id_=mc.id,
|
||||||
name=mc.name,
|
name=mc.name,
|
||||||
enabled=reduce(lambda x, y: x and (y.product_id in products), mc.products, True),
|
enabled=reduce(lambda x, y: x and (y.sku.product_id in products), mc.skus, True),
|
||||||
products=[ProductLink(id_=p.id, name=p.name) for p in mc.products if p.product_id in products],
|
skus=[
|
||||||
|
ProductLink(id_=p.sku.product_id, name=f"{p.sku.product.versions[0].name} ({p.units})")
|
||||||
|
for p in mc.skus
|
||||||
|
if p.sku.product_id in products
|
||||||
|
],
|
||||||
)
|
)
|
||||||
for mc in menu_categories
|
for mc in menu_categories
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
modifier_category.menu_categories = [i for i in modifier_category.menu_categories if len(i.products) > 0]
|
modifier_category.menu_categories = [i for i in modifier_category.menu_categories if len(i.skus) > 0]
|
||||||
modifier_categories.append(modifier_category)
|
modifier_categories.append(modifier_category)
|
||||||
return modifier_categories
|
return modifier_categories
|
||||||
|
|
||||||
@@ -198,7 +228,7 @@ def show_id(
|
|||||||
|
|
||||||
def modifier_category_info(item: ModifierCategory, date_: date, db: Session) -> schemas.ModifierCategory:
|
def modifier_category_info(item: ModifierCategory, date_: date, db: Session) -> schemas.ModifierCategory:
|
||||||
product_version_onclause = and_(
|
product_version_onclause = and_(
|
||||||
ProductVersion.menu_category_id == MenuCategory.id,
|
ProductVersion.product_id == Product.id,
|
||||||
or_(
|
or_(
|
||||||
ProductVersion.valid_from == None, # noqa: E711
|
ProductVersion.valid_from == None, # noqa: E711
|
||||||
ProductVersion.valid_from <= date_,
|
ProductVersion.valid_from <= date_,
|
||||||
@@ -208,18 +238,42 @@ def modifier_category_info(item: ModifierCategory, date_: date, db: Session) ->
|
|||||||
ProductVersion.valid_till >= date_,
|
ProductVersion.valid_till >= date_,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
sku_version_onclause = and_(
|
||||||
|
SkuVersion.sku_id == StockKeepingUnit.id,
|
||||||
|
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711
|
||||||
|
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711
|
||||||
|
)
|
||||||
|
sku_version_menu_category_onclause = and_(
|
||||||
|
SkuVersion.menu_category_id == MenuCategory.id,
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_from == None, # noqa: E711
|
||||||
|
SkuVersion.valid_from <= date_,
|
||||||
|
),
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_till == None, # noqa: E711
|
||||||
|
SkuVersion.valid_till >= date_,
|
||||||
|
),
|
||||||
|
)
|
||||||
menu_categories = (
|
menu_categories = (
|
||||||
db.execute(
|
db.execute(
|
||||||
select(MenuCategory)
|
select(MenuCategory)
|
||||||
|
.join(SkuVersion, onclause=sku_version_menu_category_onclause)
|
||||||
|
.join(StockKeepingUnit, onclause=sku_version_onclause)
|
||||||
|
.join(StockKeepingUnit.product)
|
||||||
.join(ProductVersion, onclause=product_version_onclause)
|
.join(ProductVersion, onclause=product_version_onclause)
|
||||||
.order_by(MenuCategory.sort_order, ProductVersion.sort_order, ProductVersion.name)
|
.order_by(MenuCategory.sort_order, StockKeepingUnit.sort_order, ProductVersion.name)
|
||||||
.options(contains_eager(MenuCategory.products))
|
.options(
|
||||||
|
contains_eager(MenuCategory.skus)
|
||||||
|
.contains_eager(SkuVersion.sku)
|
||||||
|
.contains_eager(StockKeepingUnit.product)
|
||||||
|
.contains_eager(Product.versions)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.unique()
|
.unique()
|
||||||
.scalars()
|
.scalars()
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
products = [p.id for p in item.products]
|
products = [x.id for x in item.products]
|
||||||
return schemas.ModifierCategory(
|
return schemas.ModifierCategory(
|
||||||
id_=item.id,
|
id_=item.id,
|
||||||
name=item.name,
|
name=item.name,
|
||||||
@@ -230,13 +284,13 @@ def modifier_category_info(item: ModifierCategory, date_: date, db: Session) ->
|
|||||||
schemas.MenuCategoryLink(
|
schemas.MenuCategoryLink(
|
||||||
id_=mc.id,
|
id_=mc.id,
|
||||||
name=mc.name,
|
name=mc.name,
|
||||||
products=[
|
skus=[
|
||||||
ProductLinkSchema(
|
ProductLink(
|
||||||
id_=p.product_id,
|
id_=p.sku.product_id,
|
||||||
name=p.name,
|
name=f"{p.sku.product.versions[0].name} ({p.units})",
|
||||||
enabled=p.product_id in products,
|
enabled=p.sku.product_id in products,
|
||||||
)
|
)
|
||||||
for p in mc.products
|
for p in mc.skus
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
for mc in menu_categories
|
for mc in menu_categories
|
||||||
@@ -247,7 +301,7 @@ def modifier_category_info(item: ModifierCategory, date_: date, db: Session) ->
|
|||||||
|
|
||||||
def modifier_category_blank(date_: date, db: Session) -> schemas.ModifierCategoryBlank:
|
def modifier_category_blank(date_: date, db: Session) -> schemas.ModifierCategoryBlank:
|
||||||
product_version_onclause = and_(
|
product_version_onclause = and_(
|
||||||
ProductVersion.menu_category_id == MenuCategory.id,
|
ProductVersion.product_id == Product.id,
|
||||||
or_(
|
or_(
|
||||||
ProductVersion.valid_from == None, # noqa: E711
|
ProductVersion.valid_from == None, # noqa: E711
|
||||||
ProductVersion.valid_from <= date_,
|
ProductVersion.valid_from <= date_,
|
||||||
@@ -257,12 +311,36 @@ def modifier_category_blank(date_: date, db: Session) -> schemas.ModifierCategor
|
|||||||
ProductVersion.valid_till >= date_,
|
ProductVersion.valid_till >= date_,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
sku_version_onclause = and_(
|
||||||
|
SkuVersion.sku_id == StockKeepingUnit.id,
|
||||||
|
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711
|
||||||
|
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711
|
||||||
|
)
|
||||||
|
sku_version_menu_category_onclause = and_(
|
||||||
|
SkuVersion.menu_category_id == MenuCategory.id,
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_from == None, # noqa: E711
|
||||||
|
SkuVersion.valid_from <= date_,
|
||||||
|
),
|
||||||
|
or_(
|
||||||
|
SkuVersion.valid_till == None, # noqa: E711
|
||||||
|
SkuVersion.valid_till >= date_,
|
||||||
|
),
|
||||||
|
)
|
||||||
menu_categories = (
|
menu_categories = (
|
||||||
db.execute(
|
db.execute(
|
||||||
select(MenuCategory)
|
select(MenuCategory)
|
||||||
|
.join(SkuVersion, onclause=sku_version_menu_category_onclause)
|
||||||
|
.join(StockKeepingUnit, onclause=sku_version_onclause)
|
||||||
|
.join(StockKeepingUnit.product)
|
||||||
.join(ProductVersion, onclause=product_version_onclause)
|
.join(ProductVersion, onclause=product_version_onclause)
|
||||||
.order_by(MenuCategory.sort_order, ProductVersion.sort_order, ProductVersion.name)
|
.order_by(MenuCategory.sort_order, StockKeepingUnit.sort_order, ProductVersion.name)
|
||||||
.options(contains_eager(MenuCategory.products))
|
.options(
|
||||||
|
contains_eager(MenuCategory.skus)
|
||||||
|
.contains_eager(SkuVersion.sku)
|
||||||
|
.contains_eager(StockKeepingUnit.product)
|
||||||
|
.contains_eager(Product.versions)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.unique()
|
.unique()
|
||||||
.scalars()
|
.scalars()
|
||||||
@@ -277,16 +355,21 @@ def modifier_category_blank(date_: date, db: Session) -> schemas.ModifierCategor
|
|||||||
schemas.MenuCategoryLink(
|
schemas.MenuCategoryLink(
|
||||||
id_=mc.id,
|
id_=mc.id,
|
||||||
name=mc.name,
|
name=mc.name,
|
||||||
products=[ProductLinkSchema(id_=p.product_id, name=p.name, enabled=False) for p in mc.products],
|
skus=[
|
||||||
|
ProductLinkSchema(
|
||||||
|
id_=p.sku.product_id, name=f"{p.sku.product.versions[0].name} ({p.units})", enabled=False
|
||||||
|
)
|
||||||
|
for p in mc.skus
|
||||||
|
],
|
||||||
)
|
)
|
||||||
for mc in menu_categories
|
for mc in menu_categories
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_products(modifier_category: ModifierCategory, menu_categories: list[MenuCategoryLink], db: Session) -> None:
|
def add_skus(modifier_category: ModifierCategory, menu_categories: list[MenuCategoryLink], db: Session) -> None:
|
||||||
for mc in menu_categories:
|
for mc in menu_categories:
|
||||||
for p in mc.products:
|
for p in mc.skus:
|
||||||
old = next((x for x in modifier_category.products if x.id == p.id_), None)
|
old = next((x for x in modifier_category.products if x.id == p.id_), None)
|
||||||
if p.enabled and old is None:
|
if p.enabled and old is None:
|
||||||
product_object = db.execute(select(Product).where(Product.id == p.id_)).scalar_one()
|
product_object = db.execute(select(Product).where(Product.id == p.id_)).scalar_one()
|
||||||
|
|||||||
@@ -28,5 +28,5 @@ class MenuCategoryLink(BaseModel):
|
|||||||
id_: uuid.UUID = Field(...)
|
id_: uuid.UUID = Field(...)
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
enabled: bool | None = None
|
enabled: bool | None = None
|
||||||
products: list[ProductLink]
|
skus: list[ProductLink]
|
||||||
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { StockKeepingUnit as Product } from './stock-keeping-unit';
|
import { StockKeepingUnit } from './product';
|
||||||
|
|
||||||
export class MenuCategory {
|
export class MenuCategory {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
@@ -6,7 +6,7 @@ export class MenuCategory {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
isFixture: boolean;
|
isFixture: boolean;
|
||||||
sortOrder: number;
|
sortOrder: number;
|
||||||
products: Product[];
|
skus: StockKeepingUnit[];
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
|
||||||
public constructor(init?: Partial<MenuCategory>) {
|
public constructor(init?: Partial<MenuCategory>) {
|
||||||
@@ -15,7 +15,7 @@ export class MenuCategory {
|
|||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
this.isFixture = false;
|
this.isFixture = false;
|
||||||
this.sortOrder = 0;
|
this.sortOrder = 0;
|
||||||
this.products = [];
|
this.skus = [];
|
||||||
Object.assign(this, init);
|
Object.assign(this, init);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,32 @@
|
|||||||
import { MenuCategory } from './menu-category';
|
|
||||||
import { Modifier } from './modifier';
|
import { Modifier } from './modifier';
|
||||||
|
|
||||||
|
export class StockKeepingUnitLink {
|
||||||
|
id: string | undefined;
|
||||||
|
name: string;
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
public constructor(init?: Partial<StockKeepingUnitLink>) {
|
||||||
|
this.name = '';
|
||||||
|
this.enabled = true;
|
||||||
|
Object.assign(this, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MenuCategory {
|
||||||
|
id: string | undefined;
|
||||||
|
name: string;
|
||||||
|
skus: StockKeepingUnitLink[];
|
||||||
|
enabled?: boolean;
|
||||||
|
|
||||||
|
public constructor(init?: Partial<MenuCategory>) {
|
||||||
|
this.id = undefined;
|
||||||
|
this.name = '';
|
||||||
|
this.enabled = true;
|
||||||
|
this.skus = [];
|
||||||
|
Object.assign(this, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ModifierCategory {
|
export class ModifierCategory {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
+14
-16
@@ -12,9 +12,7 @@ import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category';
|
||||||
import { ModifierCategory } from '../../core/modifier-category';
|
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
import { ModifierCategoryService } from '../modifier-category.service';
|
import { ModifierCategoryService } from '../modifier-category.service';
|
||||||
import { NodeItem } from '../node-item';
|
import { NodeItem } from '../node-item';
|
||||||
@@ -35,7 +33,6 @@ interface ModifierCategoryNode {
|
|||||||
styleUrls: ['./modifier-category-detail.component.css'],
|
styleUrls: ['./modifier-category-detail.component.css'],
|
||||||
imports: [
|
imports: [
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatDividerModule,
|
MatDividerModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
@@ -65,8 +62,8 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
item: ModifierCategory = new ModifierCategory();
|
item: ModifierCategory = new ModifierCategory();
|
||||||
dataSource = new MatTreeNestedDataSource<NodeItem>();
|
dataSource = new MatTreeNestedDataSource<NodeItem>();
|
||||||
products: Map<string, Product> = new Map<string, Product>();
|
products: Map<string, StockKeepingUnitLink> = new Map<string, StockKeepingUnitLink>();
|
||||||
productsOfMenuCategory: Map<string, Product[]> = new Map<string, Product[]>();
|
productsOfMenuCategory: Map<string, StockKeepingUnitLink[]> = new Map<string, StockKeepingUnitLink[]>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Create form
|
// Create form
|
||||||
@@ -87,7 +84,7 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
|
|||||||
const tree: NodeItem[] = data.item.menuCategories.map((x: MenuCategory) => ({
|
const tree: NodeItem[] = data.item.menuCategories.map((x: MenuCategory) => ({
|
||||||
id: x.id as string,
|
id: x.id as string,
|
||||||
name: x.name,
|
name: x.name,
|
||||||
children: x.products.map((y: Product) => ({ id: y.id as string, name: y.name })),
|
children: x.skus.map((y: StockKeepingUnitLink) => ({ id: y.id as string, name: y.name })),
|
||||||
}));
|
}));
|
||||||
return { item: data.item, tree };
|
return { item: data.item, tree };
|
||||||
}),
|
}),
|
||||||
@@ -109,12 +106,12 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.products = new Map();
|
this.products = new Map();
|
||||||
this.productsOfMenuCategory = new Map();
|
this.productsOfMenuCategory = new Map();
|
||||||
this.item.menuCategories.forEach((mc: MenuCategory) => {
|
this.item.menuCategories.forEach((mc: MenuCategory) => {
|
||||||
mc.products.forEach((p: Product) => {
|
mc.skus.forEach((p: StockKeepingUnitLink) => {
|
||||||
this.products.set(p.id as string, p);
|
this.products.set(p.id as string, p);
|
||||||
if (!this.productsOfMenuCategory.has(mc.id as string)) {
|
if (!this.productsOfMenuCategory.has(mc.id as string)) {
|
||||||
this.productsOfMenuCategory.set(mc.id as string, []);
|
this.productsOfMenuCategory.set(mc.id as string, []);
|
||||||
}
|
}
|
||||||
(this.productsOfMenuCategory.get(mc.id as string) as Product[]).push(p);
|
(this.productsOfMenuCategory.get(mc.id as string) as StockKeepingUnitLink[]).push(p);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// this.setMenuCategories();
|
// this.setMenuCategories();
|
||||||
@@ -180,19 +177,19 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isProductSelected(node: NodeItem) {
|
isProductSelected(node: NodeItem) {
|
||||||
return (this.products.get(node.id) as Product).enabled;
|
return (this.products.get(node.id) as StockKeepingUnitLink).enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMenuCategorySelected(node: NodeItem) {
|
isMenuCategorySelected(node: NodeItem) {
|
||||||
return (this.productsOfMenuCategory.get(node.id) as Product[]).reduce(
|
return (this.productsOfMenuCategory.get(node.id) as StockKeepingUnitLink[]).reduce(
|
||||||
(acc: boolean, current: Product) => acc && current.enabled,
|
(acc: boolean, current: StockKeepingUnitLink) => acc && current.enabled,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
isMenuCategoryPartiallySelected(node: NodeItem) {
|
isMenuCategoryPartiallySelected(node: NodeItem) {
|
||||||
const total = (this.productsOfMenuCategory.get(node.id) as Product[]).length;
|
const total = (this.productsOfMenuCategory.get(node.id) as StockKeepingUnitLink[]).length;
|
||||||
const ticked = (this.productsOfMenuCategory.get(node.id) as Product[]).reduce((acc, current) => {
|
const ticked = (this.productsOfMenuCategory.get(node.id) as StockKeepingUnitLink[]).reduce((acc, current) => {
|
||||||
if (current.enabled) {
|
if (current.enabled) {
|
||||||
acc += 1;
|
acc += 1;
|
||||||
}
|
}
|
||||||
@@ -202,12 +199,13 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleProductSelection(node: NodeItem) {
|
toggleProductSelection(node: NodeItem) {
|
||||||
(this.products.get(node.id) as Product).enabled = !(this.products.get(node.id) as Product).enabled;
|
(this.products.get(node.id) as StockKeepingUnitLink).enabled = !(this.products.get(node.id) as StockKeepingUnitLink)
|
||||||
|
.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleMenuCategorySelection(node: NodeItem) {
|
toggleMenuCategorySelection(node: NodeItem) {
|
||||||
const sel = !this.isMenuCategorySelected(node);
|
const sel = !this.isMenuCategorySelected(node);
|
||||||
(this.productsOfMenuCategory.get(node.id as string) as Product[]).forEach((p) => {
|
(this.productsOfMenuCategory.get(node.id as string) as StockKeepingUnitLink[]).forEach((p) => {
|
||||||
p.enabled = sel;
|
p.enabled = sel;
|
||||||
});
|
});
|
||||||
return sel;
|
return sel;
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@
|
|||||||
{{ mc.name }}
|
{{ mc.name }}
|
||||||
@if (!mc.enabled) {
|
@if (!mc.enabled) {
|
||||||
<ul>
|
<ul>
|
||||||
@for (p of mc.products; track p) {
|
@for (p of mc.skus; track p) {
|
||||||
<li>{{ p.name }}</li>
|
<li>{{ p.name }}</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -63,13 +63,13 @@
|
|||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-checkbox formControlName="hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
|
<mat-checkbox formControlName="hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
|
||||||
<mat-checkbox formControlName="isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
|
<mat-checkbox formControlName="isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
|
||||||
|
|
||||||
<button mat-raised-button color="primary" (click)="addRow()" class="flex-auto">Add</button>
|
<button mat-raised-button color="primary" (click)="addRow()" class="flex-auto">Add</button>
|
||||||
|
</div>
|
||||||
</div></form>
|
</form>
|
||||||
<!-- SKU table -->
|
<!-- SKU table -->
|
||||||
<div class="row-container wrapped">
|
<div class="row-container wrapped">
|
||||||
<mat-table [dataSource]="dataSource" aria-label="Stock Keeping Units" class="flex-auto">
|
<mat-table [dataSource]="dataSource" aria-label="Stock Keeping Units" class="flex-auto">
|
||||||
<!-- Units Column -->
|
<!-- Units Column -->
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { CurrencyPipe } from '@angular/common';
|
||||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, inject } from '@angular/core';
|
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild, inject } from '@angular/core';
|
||||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
@@ -5,21 +6,20 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
|||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { Product, StockKeepingUnit } from '../../core/product';
|
import { Product, StockKeepingUnit } from '../../core/product';
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
import { ProductService } from '../product.service';
|
import { ProductService } from '../product.service';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
|
||||||
import { ProductDetailDatasource } from './product-detail-datasource';
|
import { ProductDetailDatasource } from './product-detail-datasource';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
|
||||||
import { CurrencyPipe } from '@angular/common';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-product-detail',
|
selector: 'app-product-detail',
|
||||||
@@ -46,7 +46,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
private ser = inject(ProductService);
|
private ser = inject(ProductService);
|
||||||
|
|
||||||
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
@ViewChild('name', { static: true }) nameElement?: ElementRef;
|
||||||
form: FormGroup<{
|
form: FormGroup<{
|
||||||
// Product fields
|
// Product fields
|
||||||
name: FormControl<string>;
|
name: FormControl<string>;
|
||||||
fractionUnits: FormControl<string>;
|
fractionUnits: FormControl<string>;
|
||||||
@@ -66,18 +66,27 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
}>;
|
}>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
menuCategories: MenuCategory[] = [];
|
menuCategories: MenuCategory[] = [];
|
||||||
saleCategories: SaleCategory[] = [];
|
saleCategories: SaleCategory[] = [];
|
||||||
public skus = new BehaviorSubject<StockKeepingUnit[]>([]);
|
public skus = new BehaviorSubject<StockKeepingUnit[]>([]);
|
||||||
dataSource: ProductDetailDatasource = new ProductDetailDatasource(this.skus);
|
dataSource: ProductDetailDatasource = new ProductDetailDatasource(this.skus);
|
||||||
item: Product = new Product();
|
item: Product = new Product();
|
||||||
|
|
||||||
displayedColumns = ['units', 'fraction', 'productYield', 'costPrice', 'salePrice', 'menuCategory', 'hasHappyHour', 'isNotAvailable', 'action'];
|
displayedColumns = [
|
||||||
|
'units',
|
||||||
|
'fraction',
|
||||||
|
'productYield',
|
||||||
|
'costPrice',
|
||||||
|
'salePrice',
|
||||||
|
'menuCategory',
|
||||||
|
'hasHappyHour',
|
||||||
|
'isNotAvailable',
|
||||||
|
'action',
|
||||||
|
];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Create form
|
// Create form
|
||||||
this.form = new FormGroup({
|
this.form = new FormGroup({
|
||||||
name: new FormControl<string>('', { nonNullable: true }),
|
name: new FormControl<string>('', { nonNullable: true }),
|
||||||
fractionUnits: new FormControl<string>('', { nonNullable: true }),
|
fractionUnits: new FormControl<string>('', { nonNullable: true }),
|
||||||
saleCategory: new FormControl<string>('', { nonNullable: true }),
|
saleCategory: new FormControl<string>('', { nonNullable: true }),
|
||||||
@@ -174,13 +183,16 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.snackBar.open('Menu Category is required', 'Error');
|
this.snackBar.open('Menu Category is required', 'Error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sku = new StockKeepingUnit({
|
const sku = new StockKeepingUnit({
|
||||||
units,
|
units,
|
||||||
fraction,
|
fraction,
|
||||||
productYield,
|
productYield,
|
||||||
costPrice,
|
costPrice,
|
||||||
salePrice,
|
salePrice,
|
||||||
menuCategory: new MenuCategory({ id: menuCategoryId, name: this.menuCategories.find((x) => x.id === menuCategoryId)?.name ?? '' }),
|
menuCategory: new MenuCategory({
|
||||||
|
id: menuCategoryId,
|
||||||
|
name: this.menuCategories.find((x) => x.id === menuCategoryId)?.name ?? '',
|
||||||
|
}),
|
||||||
hasHappyHour: formValue.hasHappyHour ?? false,
|
hasHappyHour: formValue.hasHappyHour ?? false,
|
||||||
isNotAvailable: formValue.isNotAvailable ?? false,
|
isNotAvailable: formValue.isNotAvailable ?? false,
|
||||||
});
|
});
|
||||||
@@ -203,7 +215,6 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
// isPurchased: this.item.isPurchased,
|
// isPurchased: this.item.isPurchased,
|
||||||
// },
|
// },
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// dialogRef.afterClosed().subscribe((result: boolean | StockKeepingUnit) => {
|
// dialogRef.afterClosed().subscribe((result: boolean | StockKeepingUnit) => {
|
||||||
// if (!result) {
|
// if (!result) {
|
||||||
// return;
|
// return;
|
||||||
@@ -280,14 +291,12 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (this.item.menuCategory === null || this.item.menuCategory === undefined) {
|
||||||
|
// this.item.menuCategory = new MenuCategory();
|
||||||
|
// }
|
||||||
|
// this.item.menuCategory.id = formModel.menuCategory;
|
||||||
|
|
||||||
|
// this.item.price = formModel.price ?? 0;
|
||||||
// if (this.item.menuCategory === null || this.item.menuCategory === undefined) {
|
// this.item.hasHappyHour = formModel.hasHappyHour ?? false;
|
||||||
// this.item.menuCategory = new MenuCategory();
|
// this.item.isNotAvailable = formModel.isNotAvailable ?? false;
|
||||||
// }
|
// this.item.quantity = formModel.quantity ?? 0;
|
||||||
// this.item.menuCategory.id = formModel.menuCategory;
|
|
||||||
|
|
||||||
// this.item.price = formModel.price ?? 0;
|
|
||||||
// this.item.hasHappyHour = formModel.hasHappyHour ?? false;
|
|
||||||
// this.item.isNotAvailable = formModel.isNotAvailable ?? false;
|
|
||||||
// this.item.quantity = formModel.quantity ?? 0;
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { inject } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import { ResolveFn } from '@angular/router';
|
import { ResolveFn } from '@angular/router';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../core/stock-keeping-unit';
|
import { Product } from '../core/product';
|
||||||
import { ProductService } from './product.service';
|
import { ProductService } from './product.service';
|
||||||
|
|
||||||
export const productListResolver: ResolveFn<Product[]> = () => {
|
export const productListResolver: ResolveFn<Product[]> = () => {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { DataSource } from '@angular/cdk/collections';
|
|||||||
import { merge, Observable } from 'rxjs';
|
import { merge, Observable } from 'rxjs';
|
||||||
import { map, tap } from 'rxjs/operators';
|
import { map, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
|
||||||
import { Product } from '../../core/product';
|
import { Product } from '../../core/product';
|
||||||
|
|
||||||
export class ProductListDataSource extends DataSource<Product> {
|
export class ProductListDataSource extends DataSource<Product> {
|
||||||
|
|||||||
@@ -50,8 +50,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
@for (sku of row.skus; track sku) {
|
@for (sku of row.skus; track sku) {
|
||||||
<li>
|
<li>
|
||||||
<a [routerLink]="['/products', row.id]"
|
<a [routerLink]="['/products', row.id]">{{ row.name }} ({{ sku.units }})</a>
|
||||||
>{{ row.name }} ({{ sku.units }})</a>
|
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -99,19 +98,19 @@
|
|||||||
<ul>
|
<ul>
|
||||||
@for (sku of row.skus; track sku) {
|
@for (sku of row.skus; track sku) {
|
||||||
<li layout="row">
|
<li layout="row">
|
||||||
<div>
|
<div>
|
||||||
<mat-icon>
|
<mat-icon>
|
||||||
{{ sku.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
|
{{ sku.hasHappyHour ? 'sentiment_satisfied_alt' : 'sentiment_dissatisfied' }}
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
<b> {{ sku.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
|
<b> {{ sku.hasHappyHour ? 'Happy Hour' : 'Regular' }}</b>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-icon>
|
<mat-icon>
|
||||||
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
|
{{ row.isNotAvailable ? 'pause' : 'play_arrow' }}
|
||||||
</mat-icon>
|
</mat-icon>
|
||||||
<b> {{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
|
<b> {{ row.isNotAvailable ? 'Not Available' : 'Available' }}</b>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
@@ -121,15 +120,11 @@
|
|||||||
<ng-container matColumnDef="quantity">
|
<ng-container matColumnDef="quantity">
|
||||||
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let row" class="right">
|
<mat-cell *matCellDef="let row" class="right">
|
||||||
<ul>
|
<ul>
|
||||||
@for (sku of row.skus; track sku) {
|
@for (sku of row.skus; track sku) {
|
||||||
<li>
|
<li>{{ sku.fraction | number: '1.2-2' }}{{ row.fractionUnits }}</li>
|
||||||
{{ sku.fraction | number: '1.2-2' }}{{ row.fractionUnits }}
|
|
||||||
</li>
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CdkDragDrop, moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
import { CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
import { AsyncPipe, DecimalPipe, CurrencyPipe } from '@angular/common';
|
import { AsyncPipe, DecimalPipe, CurrencyPipe } from '@angular/common';
|
||||||
import { Component, OnInit, inject } from '@angular/core';
|
import { Component, OnInit, inject } from '@angular/core';
|
||||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
|
||||||
import { Injectable, inject } from '@angular/core';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { catchError } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { ErrorLoggerService } from '../core/error-logger.service';
|
|
||||||
import { StockKeepingUnit as Product } from '../core/stock-keeping-unit';
|
|
||||||
|
|
||||||
const httpOptions = {
|
|
||||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
|
||||||
};
|
|
||||||
|
|
||||||
const url = '/api/products';
|
|
||||||
const serviceName = 'ProductService';
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
|
||||||
export class ProductService {
|
|
||||||
private http = inject(HttpClient);
|
|
||||||
private log = inject(ErrorLoggerService);
|
|
||||||
|
|
||||||
get(id: string | null): Observable<Product> {
|
|
||||||
const getUrl: string = id === null ? `${url}` : `${url}/${id}`;
|
|
||||||
return this.http
|
|
||||||
.get<Product>(getUrl)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, `get id=${id}`))) as Observable<Product>;
|
|
||||||
}
|
|
||||||
|
|
||||||
list(): Observable<Product[]> {
|
|
||||||
return this.http
|
|
||||||
.get<Product[]>(`${url}/list`)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'list'))) as Observable<Product[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
listOfSaleCategory(id: string): Observable<Product[]> {
|
|
||||||
const options = { params: new HttpParams().set('sc', id) };
|
|
||||||
return this.http
|
|
||||||
.get<Product[]>(`${url}/query`, options)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'listOfSaleCategory'))) as Observable<Product[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
listIsActiveOfCategory(id: string): Observable<Product[]> {
|
|
||||||
const options = { params: new HttpParams().set('mc', id) };
|
|
||||||
return this.http
|
|
||||||
.get<Product[]>(`${url}/query`, options)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'listIsActiveOfCategory'))) as Observable<Product[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
save(product: Product): Observable<void> {
|
|
||||||
return this.http
|
|
||||||
.post<Product>(`${url}`, product, httpOptions)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'save'))) as Observable<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(product: Product): Observable<void> {
|
|
||||||
return this.http
|
|
||||||
.put<Product>(`${url}/${product.id}`, product, httpOptions)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'update'))) as Observable<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSortOrder(list: Product[]): Observable<Product[]> {
|
|
||||||
return this.http
|
|
||||||
.post<Product[]>(`${url}/list`, list, httpOptions)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'updateSortOrder'))) as Observable<Product[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveOrUpdate(product: Product): Observable<void> {
|
|
||||||
if (!product.versionId) {
|
|
||||||
return this.save(product);
|
|
||||||
}
|
|
||||||
return this.update(product);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string): Observable<void> {
|
|
||||||
return this.http
|
|
||||||
.delete<Product>(`${url}/${id}`, httpOptions)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'delete'))) as Observable<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
balance(id: string, date: string): Observable<number> {
|
|
||||||
const options = { params: new HttpParams().set('d', date) };
|
|
||||||
return this.http
|
|
||||||
.get<number>(`${url}/balance`, options)
|
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'balance'))) as Observable<number>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { inject } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import { ResolveFn } from '@angular/router';
|
import { ResolveFn } from '@angular/router';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../core/stock-keeping-unit';
|
import { Product } from '../core/product';
|
||||||
import { ProductService } from './product.service';
|
import { ProductService } from './product.service';
|
||||||
|
|
||||||
export const productResolver: ResolveFn<Product> = (route) => {
|
export const productResolver: ResolveFn<Product> = (route) => {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { Observable } from 'rxjs';
|
|||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ErrorLoggerService } from '../core/error-logger.service';
|
import { ErrorLoggerService } from '../core/error-logger.service';
|
||||||
import { StockKeepingUnit as Product } from '../core/stock-keeping-unit';
|
import { Product } from '../core/product';
|
||||||
import { Product as ProductNew } from '../core/product';
|
|
||||||
|
|
||||||
const httpOptions = {
|
const httpOptions = {
|
||||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
|
||||||
@@ -46,25 +45,25 @@ export class ProductService {
|
|||||||
.pipe(catchError(this.log.handleError(serviceName, 'listIsActiveOfCategory'))) as Observable<Product[]>;
|
.pipe(catchError(this.log.handleError(serviceName, 'listIsActiveOfCategory'))) as Observable<Product[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
save(product: ProductNew): Observable<void> {
|
save(product: Product): Observable<void> {
|
||||||
return this.http
|
return this.http
|
||||||
.post<ProductNew>(`${url}`, product, httpOptions)
|
.post<Product>(`${url}`, product, httpOptions)
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'save'))) as Observable<void>;
|
.pipe(catchError(this.log.handleError(serviceName, 'save'))) as Observable<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(product: ProductNew): Observable<void> {
|
update(product: Product): Observable<void> {
|
||||||
return this.http
|
return this.http
|
||||||
.put<ProductNew>(`${url}/${product.id}`, product, httpOptions)
|
.put<Product>(`${url}/${product.id}`, product, httpOptions)
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'update'))) as Observable<void>;
|
.pipe(catchError(this.log.handleError(serviceName, 'update'))) as Observable<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSortOrder(list: ProductNew[]): Observable<ProductNew[]> {
|
updateSortOrder(list: Product[]): Observable<Product[]> {
|
||||||
return this.http
|
return this.http
|
||||||
.post<ProductNew[]>(`${url}/list`, list, httpOptions)
|
.post<Product[]>(`${url}/list`, list, httpOptions)
|
||||||
.pipe(catchError(this.log.handleError(serviceName, 'updateSortOrder'))) as Observable<ProductNew[]>;
|
.pipe(catchError(this.log.handleError(serviceName, 'updateSortOrder'))) as Observable<Product[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveOrUpdate(product: ProductNew): Observable<void> {
|
saveOrUpdate(product: Product): Observable<void> {
|
||||||
if (!product.versionId) {
|
if (!product.versionId) {
|
||||||
return this.save(product);
|
return this.save(product);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { inject } from '@angular/core';
|
|||||||
import { ResolveFn } from '@angular/router';
|
import { ResolveFn } from '@angular/router';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../core/stock-keeping-unit';
|
import { Product } from '../core/product';
|
||||||
import { ProductService } from '../product/product.service';
|
import { ProductService } from '../product/product.service';
|
||||||
|
|
||||||
export const productListResolver: ResolveFn<Product[]> = (route) => {
|
export const productListResolver: ResolveFn<Product[]> = (route) => {
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
|||||||
import { round } from 'mathjs';
|
import { round } from 'mathjs';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
|
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
||||||
import { Tax } from '../../core/tax';
|
import { Tax } from '../../core/tax';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
import { SaleCategoryService } from '../sale-category.service';
|
import { SaleCategoryService } from '../sale-category.service';
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import { tap } from 'rxjs/operators';
|
|||||||
|
|
||||||
import { BillViewItem } from '../core/bill-view-item';
|
import { BillViewItem } from '../core/bill-view-item';
|
||||||
import { ModifierCategory } from '../core/modifier-category';
|
import { ModifierCategory } from '../core/modifier-category';
|
||||||
import { StockKeepingUnit } from '../core/stock-keeping-unit';
|
|
||||||
import { ReceivePaymentItem } from '../core/receive-payment-item';
|
import { ReceivePaymentItem } from '../core/receive-payment-item';
|
||||||
import { SaleCategory } from '../core/sale-category';
|
import { SaleCategory } from '../core/sale-category';
|
||||||
|
import { StockKeepingUnit } from '../core/stock-keeping-unit';
|
||||||
import { Table } from '../core/table';
|
import { Table } from '../core/table';
|
||||||
import { ModifierCategoryService } from '../modifier-categories/modifier-category.service';
|
import { ModifierCategoryService } from '../modifier-categories/modifier-category.service';
|
||||||
import { MathService } from '../shared/math.service';
|
import { MathService } from '../shared/math.service';
|
||||||
@@ -104,10 +104,7 @@ export class BillService {
|
|||||||
minimum(skuId: string, happyHour: boolean): number {
|
minimum(skuId: string, happyHour: boolean): number {
|
||||||
return this.bill.kots.reduce(
|
return this.bill.kots.reduce(
|
||||||
(t, k) =>
|
(t, k) =>
|
||||||
k.inventories.reduce(
|
k.inventories.reduce((a, c) => (c.sku.id === skuId && c.isHappyHour === happyHour ? a + c.quantity : a), 0) + t,
|
||||||
(a, c) => (c.sku.id === skuId && c.isHappyHour === happyHour ? a + c.quantity : a),
|
|
||||||
0,
|
|
||||||
) + t,
|
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -264,10 +261,7 @@ export class BillService {
|
|||||||
|
|
||||||
printBill(guestBookId: string | null, voucherType: VoucherType): Observable<boolean> {
|
printBill(guestBookId: string | null, voucherType: VoucherType): Observable<boolean> {
|
||||||
const item = JSON.parse(JSON.stringify(this.bill));
|
const item = JSON.parse(JSON.stringify(this.bill));
|
||||||
const skus = item.kots.reduce(
|
const skus = item.kots.reduce((p: number, k: Kot) => p + k.inventories.filter((i) => i.quantity !== 0).length, 0);
|
||||||
(p: number, k: Kot) => p + k.inventories.filter((i) => i.quantity !== 0).length,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
if (skus === 0) {
|
if (skus === 0) {
|
||||||
return throwError(() => Error('Cannot print a blank Bill\nPlease add some products!'));
|
return throwError(() => Error('Cannot print a blank Bill\nPlease add some products!'));
|
||||||
}
|
}
|
||||||
@@ -380,9 +374,7 @@ export class BillService {
|
|||||||
.filter((x) => x.isHappyHour)
|
.filter((x) => x.isHappyHour)
|
||||||
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }));
|
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }));
|
||||||
for (const item of happyHourItems) {
|
for (const item of happyHourItems) {
|
||||||
const q = kot.inventories.find(
|
const q = kot.inventories.find((x) => !x.isHappyHour && x.sku.id === item.id && x.quantity === item.quantity);
|
||||||
(x) => !x.isHappyHour && x.sku.id === item.id && x.quantity === item.quantity,
|
|
||||||
);
|
|
||||||
if (q === undefined) {
|
if (q === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MenuCategory } from './menu-category';
|
import { MenuCategory } from '../core/menu-category';
|
||||||
import { SaleCategory } from './sale-category';
|
import { SaleCategory } from '../core/sale-category';
|
||||||
import { Tax } from './tax';
|
import { Tax } from '../core/tax';
|
||||||
|
|
||||||
export class Product {
|
export class Product {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { MatCardModule } from '@angular/material/card';
|
|||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { BillService } from '../bill.service';
|
import { BillService } from '../bill.service';
|
||||||
|
import { Product } from '../product';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-products',
|
selector: 'app-products',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { inject } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import { ResolveFn } from '@angular/router';
|
import { ResolveFn } from '@angular/router';
|
||||||
|
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
import { Product } from '../../core/product';
|
||||||
import { ProductService } from '../../product/product.service';
|
import { ProductService } from '../../product/product.service';
|
||||||
|
|
||||||
export const productsResolver: ResolveFn<Product[]> = (route) => {
|
export const productsResolver: ResolveFn<Product[]> = (route) => {
|
||||||
|
|||||||
+1
-1
@@ -13,8 +13,8 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
|
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
import { TemporalProductService } from '../temporal-product.service';
|
import { TemporalProductService } from '../temporal-product.service';
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,8 +3,8 @@ import { merge, Observable } from 'rxjs';
|
|||||||
import { map, tap } from 'rxjs/operators';
|
import { map, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
|
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
||||||
|
|
||||||
export class TemporalProductListDatasource extends DataSource<Product> {
|
export class TemporalProductListDatasource extends DataSource<Product> {
|
||||||
public data: Product[][];
|
public data: Product[][];
|
||||||
|
|||||||
+1
-1
@@ -12,8 +12,8 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|||||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
|
import { StockKeepingUnit as Product } from '../../core/stock-keeping-unit';
|
||||||
import { TemporalProductListDatasource } from './temporal-product-list-datasource';
|
import { TemporalProductListDatasource } from './temporal-product-list-datasource';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
Reference in new issue
Block a user