fasd
This commit is contained in:
1 parent
af07bb5043
commit
103983846d
76 files changed
+415
-473
No files matched your search
Vendored
+1
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"python.defaultInterpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
|
"python.defaultInterpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
|
||||||
|
"python.terminal.useEnvFile": true,
|
||||||
"python.interpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
|
"python.interpreterPath": "/home/tanshu/programming/barker/barker/.venv/bin/python",
|
||||||
"python.venvFolders": [
|
"python.venvFolders": [
|
||||||
"barker/.venv",
|
"barker/.venv",
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@ SQLALCHEMY_DATABASE_URI=postgresql+psycopg://postgres:123456@postgres:5432/petty
|
|||||||
MODULE_NAME=barker.main
|
MODULE_NAME=barker.main
|
||||||
PROJECT_NAME=barker
|
PROJECT_NAME=barker
|
||||||
MAX_WORKERS=4
|
MAX_WORKERS=4
|
||||||
REDIS_HOST=valkey
|
NATS_HOST=nats
|
||||||
REDIS_PORT=6379
|
NATS_PORT=4222
|
||||||
SECRET_KEY={{ secret_key }}
|
SECRET_KEY={{ secret_key }}
|
||||||
MIDDLEWARE_SECRET_KEY={{ middleware_key }}
|
MIDDLEWARE_SECRET_KEY={{ middleware_key }}
|
||||||
ALGORITHM=HS256
|
ALGORITHM=HS256
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
REDIS_HOST=localhost
|
NATS_HOST=localhost
|
||||||
REDIS_PORT=6379
|
NATS_PORT=4222
|
||||||
QUEUE_NAME={{ queue_name }}
|
QUEUE_NAME={{ queue_name }}
|
||||||
@@ -1,11 +1,33 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
from nats.js.api import StreamConfig
|
||||||
|
from taskiq import BrokerMessage
|
||||||
from taskiq_nats import PullBasedJetStreamBroker
|
from taskiq_nats import PullBasedJetStreamBroker
|
||||||
|
|
||||||
from .config import settings
|
from .config import settings
|
||||||
|
|
||||||
|
|
||||||
broker = PullBasedJetStreamBroker(settings.NATS_URL)
|
class RoutedJetStreamBroker(PullBasedJetStreamBroker):
|
||||||
|
async def kick(self, message: BrokerMessage) -> None:
|
||||||
|
subject = message.labels.get("queue", self.subject)
|
||||||
|
await self.js.publish(
|
||||||
|
subject,
|
||||||
|
payload=message.message,
|
||||||
|
headers=message.labels,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
broker = RoutedJetStreamBroker(
|
||||||
|
settings.NATS_URL,
|
||||||
|
subject="barker.print.>",
|
||||||
|
stream_name="barker_print_stream",
|
||||||
|
stream_config=StreamConfig(
|
||||||
|
name="barker_print_stream",
|
||||||
|
subjects=["barker.print.>"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
main_loop: asyncio.AbstractEventLoop | None = None
|
||||||
|
|
||||||
|
|
||||||
@broker.task(task_name="sent_to_printer")
|
@broker.task(task_name="sent_to_printer")
|
||||||
@@ -14,15 +36,21 @@ async def sent_to_printer(data: str, address: str, cut_code: str) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def enqueue_print_job_sync(printer_name: str, data: str, address: str, cut_code: str) -> None:
|
def enqueue_print_job_sync(printer_name: str, data: str, address: str, cut_code: str) -> None:
|
||||||
async def _enqueue() -> None:
|
coro = sent_to_printer.kicker().with_labels(queue=f"barker.print.{printer_name}").kiq(data, address, cut_code)
|
||||||
await broker.startup()
|
|
||||||
try:
|
|
||||||
await (
|
|
||||||
sent_to_printer.kicker().with_labels(queue=f"barker.print.{printer_name}").kiq(data, address, cut_code)
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
await broker.shutdown()
|
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
if main_loop is not None and main_loop.is_running():
|
||||||
loop.run_until_complete(_enqueue())
|
asyncio.run_coroutine_threadsafe(coro, main_loop)
|
||||||
loop.close()
|
else:
|
||||||
|
|
||||||
|
async def _enqueue() -> None:
|
||||||
|
await broker.startup()
|
||||||
|
try:
|
||||||
|
await coro
|
||||||
|
finally:
|
||||||
|
await broker.shutdown()
|
||||||
|
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
try:
|
||||||
|
loop.run_until_complete(_enqueue())
|
||||||
|
finally:
|
||||||
|
loop.close()
|
||||||
+17
-2
@@ -1,5 +1,9 @@
|
|||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from collections.abc import AsyncIterator
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
@@ -7,6 +11,7 @@ from fastapi.responses import JSONResponse
|
|||||||
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
|
||||||
from starlette.middleware.sessions import SessionMiddleware
|
from starlette.middleware.sessions import SessionMiddleware
|
||||||
|
|
||||||
|
from .core import taskiq
|
||||||
from .core.config import settings
|
from .core.config import settings
|
||||||
from .db.base import reg # noqa: F401
|
from .db.base import reg # noqa: F401
|
||||||
from .db.friendly_db_error import constraint_to_friendly
|
from .db.friendly_db_error import constraint_to_friendly
|
||||||
@@ -60,8 +65,18 @@ from .routers.voucher import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
|
||||||
|
taskiq.main_loop = asyncio.get_running_loop()
|
||||||
|
await taskiq.broker.startup()
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
await taskiq.broker.shutdown()
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
app = FastAPI()
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(SQLAlchemyError)
|
@app.exception_handler(SQLAlchemyError)
|
||||||
@@ -151,4 +166,4 @@ app.frontend("/", directory="frontend", check_dir="auto")
|
|||||||
|
|
||||||
|
|
||||||
def init() -> None:
|
def init() -> None:
|
||||||
uvicorn.run(app, host=settings.HOST, port=settings.PORT)
|
uvicorn.run(app, host=settings.HOST, port=9995)
|
||||||
@@ -5,7 +5,7 @@ import { CanActivateFn, Router } from '@angular/router';
|
|||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
export const authGuard: CanActivateFn = (route, state) => {
|
export const authGuard: CanActivateFn = (route, state) => {
|
||||||
const user = inject(AuthService).user;
|
const user = inject(AuthService).user();
|
||||||
const permission =
|
const permission =
|
||||||
route.data['permission'] === undefined
|
route.data['permission'] === undefined
|
||||||
? route.data['permission']
|
? route.data['permission']
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable, inject } from '@angular/core';
|
import { Injectable, computed, inject, signal } from '@angular/core';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { environment } from '../app.environment';
|
import { environment } from '../app.environment';
|
||||||
@@ -18,14 +17,22 @@ export class AuthService {
|
|||||||
private http = inject(HttpClient);
|
private http = inject(HttpClient);
|
||||||
private cs = inject(CookieService);
|
private cs = inject(CookieService);
|
||||||
|
|
||||||
public currentUser: Observable<User | null>;
|
private _user = signal<User | null>(this.readStorage());
|
||||||
|
public user = this._user.asReadonly();
|
||||||
|
public isLoggedIn = computed(() => this.user() !== null);
|
||||||
|
|
||||||
|
private _needsRefreshing = signal<boolean>(false);
|
||||||
|
public needsRefreshing = this._needsRefreshing.asReadonly();
|
||||||
|
|
||||||
public device: Device;
|
public device: Device;
|
||||||
private currentUserSubject: BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null);
|
public isRefreshing = signal<boolean>(false);
|
||||||
public isRefreshing = false;
|
private expirationTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
private refreshTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.checkStorage();
|
const user = this._user();
|
||||||
this.currentUser = this.currentUserSubject.asObservable();
|
this.scheduleExpiryTimer(user);
|
||||||
|
this.scheduleRefreshTimer(user);
|
||||||
const deviceId = this.cs.getCookie('device_id');
|
const deviceId = this.cs.getCookie('device_id');
|
||||||
const device = this.cs.getCookie('device');
|
const device = this.cs.getCookie('device');
|
||||||
const section = this.cs.getCookie('section');
|
const section = this.cs.getCookie('section');
|
||||||
@@ -58,38 +65,71 @@ export class AuthService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
checkStorage(): User | null {
|
private readStorage(): User | null {
|
||||||
const storageToken = localStorage.getItem(JWT_USER);
|
const storageToken = localStorage.getItem(JWT_USER);
|
||||||
let existingToken: User | null = null;
|
if (!storageToken) {
|
||||||
if (storageToken !== null) {
|
return null;
|
||||||
existingToken = JSON.parse(storageToken);
|
|
||||||
}
|
}
|
||||||
if (existingToken === null || Date.now() > existingToken.exp * 1000) {
|
try {
|
||||||
|
const token: User = JSON.parse(storageToken);
|
||||||
|
if (!token || Date.now() > token.exp * 1000) {
|
||||||
|
localStorage.removeItem(JWT_USER);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
} catch {
|
||||||
localStorage.removeItem(JWT_USER);
|
localStorage.removeItem(JWT_USER);
|
||||||
this.currentUserSubject.next(null);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
this.currentUserSubject.next(existingToken);
|
|
||||||
return existingToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get user(): User | null {
|
private scheduleExpiryTimer(user: User | null): void {
|
||||||
let val = this.currentUserSubject.value;
|
if (this.expirationTimer) {
|
||||||
if (val == null) {
|
clearTimeout(this.expirationTimer);
|
||||||
return val;
|
this.expirationTimer = null;
|
||||||
}
|
}
|
||||||
let expired = Date.now() > val.exp * 1000;
|
if (!user || !user.exp) {
|
||||||
if (expired) {
|
return;
|
||||||
val = this.checkStorage();
|
|
||||||
}
|
}
|
||||||
if (val == null) {
|
const expiresInMs = user.exp * 1000 - Date.now();
|
||||||
return new User();
|
if (expiresInMs <= 0) {
|
||||||
}
|
|
||||||
expired = Date.now() > val.exp * 1000;
|
|
||||||
if (expired) {
|
|
||||||
this.logout();
|
this.logout();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return this.currentUserSubject.value;
|
this.expirationTimer = setTimeout(() => {
|
||||||
|
this.logout();
|
||||||
|
}, expiresInMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private scheduleRefreshTimer(user: User | null): void {
|
||||||
|
if (this.refreshTimer) {
|
||||||
|
clearTimeout(this.refreshTimer);
|
||||||
|
this.refreshTimer = null;
|
||||||
|
}
|
||||||
|
if (!user || !user.exp) {
|
||||||
|
this._needsRefreshing.set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const refreshInMs = (user.exp - environment.ACCESS_TOKEN_REFRESH_MINUTES * 60) * 1000 - Date.now();
|
||||||
|
if (refreshInMs <= 0) {
|
||||||
|
this._needsRefreshing.set(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._needsRefreshing.set(false);
|
||||||
|
this.refreshTimer = setTimeout(() => {
|
||||||
|
this._needsRefreshing.set(true);
|
||||||
|
}, refreshInMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveUser(user: User | null): void {
|
||||||
|
if (user) {
|
||||||
|
localStorage.setItem(JWT_USER, JSON.stringify(user));
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(JWT_USER);
|
||||||
|
}
|
||||||
|
this._user.set(user);
|
||||||
|
this.scheduleExpiryTimer(user);
|
||||||
|
this.scheduleRefreshTimer(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
login(username: string, password: string) {
|
login(username: string, password: string) {
|
||||||
@@ -103,26 +143,14 @@ export class AuthService {
|
|||||||
.pipe(map((u) => AuthService.parseJwt(u)))
|
.pipe(map((u) => AuthService.parseJwt(u)))
|
||||||
.pipe(
|
.pipe(
|
||||||
map((user) => {
|
map((user) => {
|
||||||
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
this.saveUser(user);
|
||||||
localStorage.setItem(JWT_USER, JSON.stringify(user));
|
|
||||||
this.currentUserSubject.next(user);
|
|
||||||
return user;
|
return user;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
needsRefreshing(): boolean {
|
logout(): void {
|
||||||
const { user } = this;
|
this.saveUser(null);
|
||||||
if (user === null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return Date.now() > (user.exp - environment.ACCESS_TOKEN_REFRESH_MINUTES * 60) * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
logout() {
|
|
||||||
// remove user from local storage to log user out
|
|
||||||
localStorage.removeItem(JWT_USER);
|
|
||||||
this.currentUserSubject.next(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshToken() {
|
refreshToken() {
|
||||||
@@ -132,16 +160,14 @@ export class AuthService {
|
|||||||
.pipe(map((u) => AuthService.parseJwt(u)))
|
.pipe(map((u) => AuthService.parseJwt(u)))
|
||||||
.pipe(
|
.pipe(
|
||||||
map((user) => {
|
map((user) => {
|
||||||
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
this.saveUser(user);
|
||||||
localStorage.setItem(JWT_USER, JSON.stringify(user));
|
|
||||||
this.currentUserSubject.next(user);
|
|
||||||
return user;
|
return user;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed(permission: string): boolean {
|
allowed(permission: string): boolean {
|
||||||
const { user } = this;
|
const user = this.user();
|
||||||
if (user == null || user.perms.indexOf(permission) === -1) {
|
if (user == null || user.perms.indexOf(permission) === -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Sale Category</mat-label>
|
<mat-label>Sale Category</mat-label>
|
||||||
<mat-select [formField]="form.saleCategory" (selectionChange)="filterOn($event.value)">
|
<mat-select [formField]="form.saleCategory">
|
||||||
@for (sc of saleCategories(); track sc) {
|
@for (sc of saleCategories(); track sc) {
|
||||||
<mat-option [value]="sc.id">
|
<mat-option [value]="sc.id">
|
||||||
{{ sc.name }}
|
{{ sc.name }}
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ 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 { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { SaleCategory } from '../core/sale-category';
|
|
||||||
import { SaleCategoryService } from '../sale-category/sale-category.service';
|
import { SaleCategoryService } from '../sale-category/sale-category.service';
|
||||||
import { ToCsvService } from '../shared/to-csv.service';
|
import { ToCsvService } from '../shared/to-csv.service';
|
||||||
import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface';
|
import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface';
|
||||||
@@ -48,7 +47,6 @@ export interface BeerSaleReportFormData {
|
|||||||
})
|
})
|
||||||
export class BeerSaleReportComponent {
|
export class BeerSaleReportComponent {
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private ser = inject(BeerSaleReportService);
|
private ser = inject(BeerSaleReportService);
|
||||||
private saleCategoryService = inject(SaleCategoryService);
|
private saleCategoryService = inject(SaleCategoryService);
|
||||||
@@ -125,22 +123,13 @@ export class BeerSaleReportComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
filterOn(id: string) {
|
|
||||||
const sc = this.saleCategories().find((x: SaleCategory) => x.id === id);
|
|
||||||
const currentInfo = this.info();
|
|
||||||
if (currentInfo) {
|
|
||||||
currentInfo.saleCategory = sc ? sc : new SaleCategory({ id });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getInfo(): BeerSaleReport {
|
getInfo(): BeerSaleReport {
|
||||||
const formModel = this.formModel();
|
const formModel = this.formModel();
|
||||||
const currentInfo = this.info();
|
|
||||||
|
|
||||||
return new BeerSaleReport({
|
return new BeerSaleReport({
|
||||||
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
|
startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
|
||||||
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
|
finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
|
||||||
saleCategory: currentInfo?.saleCategory,
|
saleCategory: this.saleCategories().find((sc) => sc.id === formModel.saleCategory),
|
||||||
regular: formModel.regular,
|
regular: formModel.regular,
|
||||||
happy: formModel.happy,
|
happy: formModel.happy,
|
||||||
staff: formModel.staff,
|
staff: formModel.staff,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { LocalTimePipe } from '../shared/local-time.pipe';
|
import { LocalTimePipe } from '../shared/local-time.pipe';
|
||||||
@@ -38,7 +38,6 @@ export interface BillSettlementReportFormData {
|
|||||||
})
|
})
|
||||||
export class BillSettlementReportComponent {
|
export class BillSettlementReportComponent {
|
||||||
private billSettlementReportService = inject(BillSettlementReportService);
|
private billSettlementReportService = inject(BillSettlementReportService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Menu Category</mat-label>
|
<mat-label>Menu Category</mat-label>
|
||||||
<mat-select [formField]="form.menuCategory" (selectionChange)="filterOn($event.value)">
|
<mat-select [formField]="form.menuCategory">
|
||||||
<mat-option>-- All Bundles --</mat-option>
|
<mat-option>-- All Bundles --</mat-option>
|
||||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class BundleListComponent {
|
|||||||
menuCategoriesResource = this.menuCategoryService.list();
|
menuCategoriesResource = this.menuCategoryService.list();
|
||||||
listResource = this.bundleService.list();
|
listResource = this.bundleService.list();
|
||||||
|
|
||||||
menuCategoryFilter = signal<string>('');
|
menuCategoryFilter = computed(() => this.formModel().menuCategory);
|
||||||
|
|
||||||
formModel = signal<BundleListFormData>({
|
formModel = signal<BundleListFormData>({
|
||||||
menuCategory: '',
|
menuCategory: '',
|
||||||
@@ -69,10 +69,6 @@ export class BundleListComponent {
|
|||||||
|
|
||||||
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'items'];
|
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'items'];
|
||||||
|
|
||||||
filterOn(val: string) {
|
|
||||||
this.menuCategoryFilter.set(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
exportCsv() {
|
exportCsv() {
|
||||||
const headers = {
|
const headers = {
|
||||||
Name: 'name',
|
Name: 'name',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { User } from '../core/user';
|
import { User } from '../core/user';
|
||||||
@@ -42,7 +42,6 @@ export interface CashierReportFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CashierReportComponent {
|
export class CashierReportComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { AuthService } from '../auth/auth.service';
|
|||||||
|
|
||||||
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
|
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
|
||||||
// add authorization header with jwt token if available
|
// add authorization header with jwt token if available
|
||||||
const currentUser = inject(AuthService).user;
|
const currentUser = inject(AuthService).user();
|
||||||
if (currentUser?.access_token) {
|
if (currentUser?.access_token) {
|
||||||
req = req.clone({
|
req = req.clone({
|
||||||
setHeaders: {
|
setHeaders: {
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import { AuthService } from '../auth/auth.service';
|
|||||||
|
|
||||||
export const refreshInterceptor: HttpInterceptorFn = (req, next) => {
|
export const refreshInterceptor: HttpInterceptorFn = (req, next) => {
|
||||||
const authService = inject(AuthService);
|
const authService = inject(AuthService);
|
||||||
if (!authService.isRefreshing && authService.user && authService.needsRefreshing()) {
|
if (!authService.isRefreshing() && authService.user() && authService.needsRefreshing()) {
|
||||||
authService.isRefreshing = true;
|
authService.isRefreshing.set(true);
|
||||||
authService.refreshToken().subscribe({
|
authService.refreshToken().subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
authService.isRefreshing = false;
|
authService.isRefreshing.set(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatDividerModule } from '@angular/material/divider';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { round } from 'mathjs';
|
import { round } from 'mathjs';
|
||||||
|
|
||||||
import { Customer } from '../../core/customer';
|
import { Customer } from '../../core/customer';
|
||||||
@@ -40,7 +40,6 @@ export interface CustomerDetailFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CustomerDetailComponent {
|
export class CustomerDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
@@ -65,8 +64,6 @@ export class CustomerDetailComponent {
|
|||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
hide = true;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
afterNextRender(() => {
|
afterNextRender(() => {
|
||||||
this.form().focusBoundControl();
|
this.form().focusBoundControl();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Device } from '../../core/device';
|
import { Device } from '../../core/device';
|
||||||
import { Section } from '../../core/section';
|
import { Section } from '../../core/section';
|
||||||
@@ -40,7 +40,6 @@ export interface DeviceDetailFormData {
|
|||||||
})
|
})
|
||||||
export class DeviceDetailComponent {
|
export class DeviceDetailComponent {
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { LocalTimePipe } from '../../shared/local-time.pipe';
|
import { LocalTimePipe } from '../../shared/local-time.pipe';
|
||||||
import { DeviceService } from '../device.service';
|
import { DeviceService } from '../device.service';
|
||||||
@@ -14,7 +14,6 @@ import { DeviceService } from '../device.service';
|
|||||||
})
|
})
|
||||||
export class DeviceListComponent {
|
export class DeviceListComponent {
|
||||||
private deviceService = inject(DeviceService);
|
private deviceService = inject(DeviceService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.deviceService.list();
|
listResource = this.deviceService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { ToCsvService } from '../shared/to-csv.service';
|
import { ToCsvService } from '../shared/to-csv.service';
|
||||||
@@ -36,7 +36,6 @@ export interface DiscountReportFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class DiscountReportComponent {
|
export class DiscountReportComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTimepickerModule } from '@angular/material/timepicker';
|
import { MatTimepickerModule } from '@angular/material/timepicker';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { Customer } from '../../core/customer';
|
import { Customer } from '../../core/customer';
|
||||||
@@ -44,7 +44,6 @@ export interface GuestBookDetailFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class GuestBookDetailComponent {
|
export class GuestBookDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@@ -37,7 +36,6 @@ export interface GuestBookListFormData {
|
|||||||
export class GuestBookListComponent {
|
export class GuestBookListComponent {
|
||||||
private route = inject(ActivatedRoute);
|
private route = inject(ActivatedRoute);
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
|
||||||
private ser = inject(GuestBookService);
|
private ser = inject(GuestBookService);
|
||||||
|
|
||||||
date = input(new Date(), {
|
date = input(new Date(), {
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import { Component, computed, inject, linkedSignal, input } from '@angular/core'
|
|||||||
import { form, FormField } from '@angular/forms/signals';
|
import { form, FormField } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
|
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { HeaderFooter } from './header-footer';
|
import { HeaderFooter } from './header-footer';
|
||||||
import { HeaderFooterService } from './header-footer.service';
|
import { HeaderFooterService } from './header-footer.service';
|
||||||
@@ -33,10 +32,8 @@ export interface HeaderFooterFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class HeaderFooterComponent {
|
export class HeaderFooterComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
|
||||||
private ser = inject(HeaderFooterService);
|
private ser = inject(HeaderFooterService);
|
||||||
id = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
id = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||||
listResource = this.ser.list();
|
listResource = this.ser.list();
|
||||||
|
|||||||
@@ -198,7 +198,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>
|
<p>
|
||||||
Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }} on {{ auth.device.name }} @
|
Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }} on {{ auth.device.name }} @
|
||||||
{{ auth.device.section.name }}
|
{{ auth.device.section.name }}
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -24,7 +24,6 @@ export interface MenuCategoryDetailFormData {
|
|||||||
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class MenuCategoryDetailComponent {
|
export class MenuCategoryDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
@@ -16,8 +16,6 @@ import { MenuCategoryService } from '../menu-category.service';
|
|||||||
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink],
|
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink],
|
||||||
})
|
})
|
||||||
export class MenuCategoryListComponent {
|
export class MenuCategoryListComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private ser = inject(MenuCategoryService);
|
private ser = inject(MenuCategoryService);
|
||||||
listResource = this.ser.list(undefined);
|
listResource = this.ser.list(undefined);
|
||||||
|
|||||||
+1
-7
@@ -9,7 +9,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree';
|
import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category';
|
import { ModifierCategory, MenuCategory, StockKeepingUnitLink } from '../../core/modifier-category';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -49,7 +49,6 @@ export interface ModifierCategoryDetailFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ModifierCategoryDetailComponent {
|
export class ModifierCategoryDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
@@ -112,11 +111,6 @@ export class ModifierCategoryDetailComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
isExpanded(mc: MenuCategory) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
this.ser.saveOrUpdate(this.getItem()).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
|
|||||||
+1
-2
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { ModifierCategoryService } from '../modifier-category.service';
|
import { ModifierCategoryService } from '../modifier-category.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,7 +13,6 @@ import { ModifierCategoryService } from '../modifier-category.service';
|
|||||||
})
|
})
|
||||||
export class ModifierCategoryListComponent {
|
export class ModifierCategoryListComponent {
|
||||||
private modifierCategoryService = inject(ModifierCategoryService);
|
private modifierCategoryService = inject(ModifierCategoryService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.modifierCategoryService.list();
|
listResource = this.modifierCategoryService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Modifier } from '../../core/modifier';
|
import { Modifier } from '../../core/modifier';
|
||||||
import { ModifierCategory } from '../../core/modifier-category';
|
import { ModifierCategory } from '../../core/modifier-category';
|
||||||
@@ -40,7 +40,6 @@ export interface ModifierDetailFormData {
|
|||||||
})
|
})
|
||||||
export class ModifierDetailComponent {
|
export class ModifierDetailComponent {
|
||||||
private modifierCategoryService = inject(ModifierCategoryService);
|
private modifierCategoryService = inject(ModifierCategoryService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<div class="row-container">
|
<div class="row-container">
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Modifier Category</mat-label>
|
<mat-label>Modifier Category</mat-label>
|
||||||
<mat-select (selectionChange)="filterOn($event)">
|
<mat-select [formField]="form.menuCategory">
|
||||||
<mat-option>-- All Categories --</mat-option>
|
<mat-option>-- All Categories --</mat-option>
|
||||||
@for (mc of modifierCategories(); track mc.id) {
|
@for (mc of modifierCategories(); track mc.id) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import { CurrencyPipe } from '@angular/common';
|
import { CurrencyPipe } from '@angular/common';
|
||||||
import { Component, inject, computed, signal } from '@angular/core';
|
import { Component, inject, computed, signal } from '@angular/core';
|
||||||
|
import { form, FormField } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service';
|
import { ModifierCategoryService } from '../../modifier-categories/modifier-category.service';
|
||||||
import { ModifierService } from '../modifier.service';
|
import { ModifierService } from '../modifier.service';
|
||||||
|
|
||||||
|
export interface ModifierListFormData {
|
||||||
|
menuCategory: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-modifier-list',
|
selector: 'app-modifier-list',
|
||||||
templateUrl: './modifier-list.component.html',
|
templateUrl: './modifier-list.component.html',
|
||||||
@@ -23,6 +28,7 @@ import { ModifierService } from '../modifier.service';
|
|||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
|
FormField,
|
||||||
RouterLink,
|
RouterLink,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -34,11 +40,18 @@ export class ModifierListComponent {
|
|||||||
listResource = this.modifierService.list();
|
listResource = this.modifierService.list();
|
||||||
|
|
||||||
modifierCategories = computed(() => this.modifierCategoriesResource.value() ?? []);
|
modifierCategories = computed(() => this.modifierCategoriesResource.value() ?? []);
|
||||||
filter = signal<string>('');
|
|
||||||
|
formModel = signal<ModifierListFormData>({
|
||||||
|
menuCategory: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
form = form(this.formModel);
|
||||||
|
|
||||||
|
menuCategoryFilter = computed(() => this.formModel().menuCategory);
|
||||||
|
|
||||||
dataSource = computed(() => {
|
dataSource = computed(() => {
|
||||||
const items = this.listResource.value() ?? [];
|
const items = this.listResource.value() ?? [];
|
||||||
const cat = this.filter();
|
const cat = this.menuCategoryFilter();
|
||||||
if (cat) {
|
if (cat) {
|
||||||
return items.filter((x) => x.modifierCategory?.id === cat);
|
return items.filter((x) => x.modifierCategory?.id === cat);
|
||||||
}
|
}
|
||||||
@@ -47,8 +60,4 @@ export class ModifierListComponent {
|
|||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns: string[] = ['name', 'showInBill', 'price', 'isActive', 'modifierCategory'];
|
displayedColumns: string[] = ['name', 'showInBill', 'price', 'isActive', 'modifierCategory'];
|
||||||
|
|
||||||
filterOn(val: MatSelectChange): void {
|
|
||||||
this.filter.set(val.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
@if ((auth.currentUser | async) === null) {
|
@if (auth.user() === null) {
|
||||||
<button mat-button [routerLink]="['/', 'login']">
|
<button mat-button [routerLink]="['/', 'login']">
|
||||||
<mat-icon>account_box</mat-icon>
|
<mat-icon>account_box</mat-icon>
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@if ((auth.currentUser | async)?.name; as name) {
|
@if (auth.user()?.name; as name) {
|
||||||
<button mat-button [routerLink]="['/', 'logout']">
|
<button mat-button [routerLink]="['/', 'logout']">
|
||||||
<mat-icon>account_box</mat-icon>
|
<mat-icon>account_box</mat-icon>
|
||||||
Logout {{ name }}
|
Logout {{ name }}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { AsyncPipe } from '@angular/common';
|
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
@@ -11,7 +10,7 @@ import { AuthService } from '../auth/auth.service';
|
|||||||
selector: 'app-nav-bar',
|
selector: 'app-nav-bar',
|
||||||
templateUrl: './nav-bar.component.html',
|
templateUrl: './nav-bar.component.html',
|
||||||
styleUrls: ['./nav-bar.component.css'],
|
styleUrls: ['./nav-bar.component.css'],
|
||||||
imports: [AsyncPipe, MatButtonModule, MatButtonModule, MatIconModule, MatToolbarModule, RouterLink],
|
imports: [MatButtonModule, MatIconModule, MatToolbarModule, RouterLink],
|
||||||
})
|
})
|
||||||
export class NavBarComponent {
|
export class NavBarComponent {
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Printer } from '../../core/printer';
|
import { Printer } from '../../core/printer';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -24,7 +24,6 @@ export interface PrinterDetailFormData {
|
|||||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class PrinterDetailComponent {
|
export class PrinterDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { PrinterService } from '../printer.service';
|
import { PrinterService } from '../printer.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,7 +13,6 @@ import { PrinterService } from '../printer.service';
|
|||||||
})
|
})
|
||||||
export class PrinterListComponent {
|
export class PrinterListComponent {
|
||||||
private printerService = inject(PrinterService);
|
private printerService = inject(PrinterService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.printerService.list();
|
listResource = this.printerService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { SectionService } from '../sections/section.service';
|
import { SectionService } from '../sections/section.service';
|
||||||
@@ -42,7 +42,6 @@ export interface ProductSaleReportFormData {
|
|||||||
})
|
})
|
||||||
export class ProductSaleReportComponent {
|
export class ProductSaleReportComponent {
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { ToCsvService } from '../shared/to-csv.service';
|
import { ToCsvService } from '../shared/to-csv.service';
|
||||||
@@ -34,7 +34,6 @@ export interface ProductUpdatesReportFormData {
|
|||||||
})
|
})
|
||||||
export class ProductUpdatesReportComponent {
|
export class ProductUpdatesReportComponent {
|
||||||
private productUpdatesReportService = inject(ProductUpdatesReportService);
|
private productUpdatesReportService = inject(ProductUpdatesReportService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
import { Product, StockKeepingUnit } from '../../core/product';
|
import { Product, StockKeepingUnit } from '../../core/product';
|
||||||
@@ -60,7 +60,6 @@ export interface ProductDetailFormData {
|
|||||||
export class ProductDetailComponent {
|
export class ProductDetailComponent {
|
||||||
private menuCategoryService = inject(MenuCategoryService);
|
private menuCategoryService = inject(MenuCategoryService);
|
||||||
private saleCategoryService = inject(SaleCategoryService);
|
private saleCategoryService = inject(SaleCategoryService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
@@ -258,13 +257,3 @@ export class ProductDetailComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
|
||||||
// this.item().hasHappyHour = formModel.hasHappyHour ?? false;
|
|
||||||
// this.item().isNotAvailable = formModel.isNotAvailable ?? false;
|
|
||||||
// this.item().quantity = formModel.quantity ?? 0;
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Menu Category</mat-label>
|
<mat-label>Menu Category</mat-label>
|
||||||
<mat-select [formField]="form.menuCategory" (selectionChange)="filterOn($event.value)">
|
<mat-select [formField]="form.menuCategory">
|
||||||
<mat-option>-- All Products --</mat-option>
|
<mat-option>-- All Products --</mat-option>
|
||||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ export class ProductListComponent {
|
|||||||
|
|
||||||
listResource = this.ser.list();
|
listResource = this.ser.list();
|
||||||
|
|
||||||
menuCategoryFilter = signal<string>('');
|
|
||||||
|
|
||||||
formModel = signal<ProductListFormData>({
|
formModel = signal<ProductListFormData>({
|
||||||
menuCategory: '',
|
menuCategory: '',
|
||||||
filter: '',
|
filter: '',
|
||||||
@@ -61,6 +59,8 @@ export class ProductListComponent {
|
|||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
|
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? '');
|
||||||
|
|
||||||
filterSignal = computed(() => this.formModel().filter);
|
filterSignal = computed(() => this.formModel().filter);
|
||||||
debouncedFilter = debounced(this.filterSignal, 150);
|
debouncedFilter = debounced(this.filterSignal, 150);
|
||||||
|
|
||||||
@@ -81,10 +81,6 @@ export class ProductListComponent {
|
|||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'quantity'];
|
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'quantity'];
|
||||||
|
|
||||||
filterOn(val: string): void {
|
|
||||||
this.menuCategoryFilter.set(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateSortOrder() {
|
async updateSortOrder() {
|
||||||
try {
|
try {
|
||||||
await firstValueFrom(this.ser.updateSortOrder(this.menuCategoryFilter(), this.dataSource()));
|
await firstValueFrom(this.ser.updateSortOrder(this.menuCategoryFilter(), this.dataSource()));
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Regime } from '../../core/regime';
|
import { Regime } from '../../core/regime';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -24,7 +24,6 @@ export interface RegimeDetailFormData {
|
|||||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class RegimeDetailComponent {
|
export class RegimeDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { RegimeService } from '../regime.service';
|
import { RegimeService } from '../regime.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,7 +13,6 @@ import { RegimeService } from '../regime.service';
|
|||||||
})
|
})
|
||||||
export class RegimeListComponent {
|
export class RegimeListComponent {
|
||||||
private regimeService = inject(RegimeService);
|
private regimeService = inject(RegimeService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.regimeService.list();
|
listResource = this.regimeService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
import { Role } from '../role';
|
import { Role } from '../role';
|
||||||
@@ -25,7 +25,6 @@ export interface RoleDetailFormData {
|
|||||||
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [MatButtonModule, MatCheckboxModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class RoleDetailComponent {
|
export class RoleDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { RoleService } from '../role.service';
|
import { RoleService } from '../role.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,7 +13,6 @@ import { RoleService } from '../role.service';
|
|||||||
})
|
})
|
||||||
export class RoleListComponent {
|
export class RoleListComponent {
|
||||||
private roleService = inject(RoleService);
|
private roleService = inject(RoleService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.roleService.list();
|
listResource = this.roleService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { Router, RouterLink } from '@angular/router';
|
||||||
import { round } from 'mathjs';
|
import { round } from 'mathjs';
|
||||||
|
|
||||||
import { SaleCategory } from '../../core/sale-category';
|
import { SaleCategory } from '../../core/sale-category';
|
||||||
@@ -46,7 +46,6 @@ export interface SaleCategoryDetailFormData {
|
|||||||
export class SaleCategoryDetailComponent {
|
export class SaleCategoryDetailComponent {
|
||||||
private taxService = inject(TaxService);
|
private taxService = inject(TaxService);
|
||||||
private productService = inject(ProductService);
|
private productService = inject(ProductService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ import { PercentPipe } from '@angular/common';
|
|||||||
import { Component, inject, computed } from '@angular/core';
|
import { Component, inject, computed } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { SaleCategoryService } from '../sale-category.service';
|
import { SaleCategoryService } from '../sale-category.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -14,9 +13,6 @@ import { SaleCategoryService } from '../sale-category.service';
|
|||||||
imports: [MatButtonModule, MatIconModule, MatTableModule, PercentPipe, RouterLink],
|
imports: [MatButtonModule, MatIconModule, MatTableModule, PercentPipe, RouterLink],
|
||||||
})
|
})
|
||||||
export class SaleCategoryListComponent {
|
export class SaleCategoryListComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
|
||||||
private ser = inject(SaleCategoryService);
|
private ser = inject(SaleCategoryService);
|
||||||
listResource = this.ser.list();
|
listResource = this.ser.list();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { SectionService } from '../sections/section.service';
|
import { SectionService } from '../sections/section.service';
|
||||||
@@ -43,7 +43,6 @@ export interface SaleReportFormData {
|
|||||||
})
|
})
|
||||||
export class SaleReportComponent {
|
export class SaleReportComponent {
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { form, FormField } from '@angular/forms/signals';
|
import { form, FormField } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
@@ -30,39 +30,23 @@ export interface BillNumberFormData {
|
|||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class BillNumberComponent implements OnInit {
|
export class BillNumberComponent {
|
||||||
data = inject(MAT_DIALOG_DATA);
|
regimes = inject<Regime[]>(MAT_DIALOG_DATA) ?? [];
|
||||||
dialogRef = inject<MatDialogRef<BillNumberComponent>>(MatDialogRef);
|
private dialogRef = inject<MatDialogRef<BillNumberComponent>>(MatDialogRef);
|
||||||
|
|
||||||
formModel = signal<BillNumberFormData>({
|
formModel = signal<BillNumberFormData>({
|
||||||
regime: null,
|
regime: null,
|
||||||
billNumber: null,
|
billNumber: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
regimes: Regime[] = [];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
const data = this.data;
|
|
||||||
|
|
||||||
this.regimes = data;
|
|
||||||
// Create form
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.formModel.set({
|
|
||||||
regime: null,
|
|
||||||
billNumber: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
accept(): void {
|
accept(): void {
|
||||||
const formValue = this.formModel();
|
const { regime, billNumber } = this.formModel();
|
||||||
const billNumber = formValue.billNumber ?? 0;
|
if (!regime) {
|
||||||
const regime = formValue.regime ?? null;
|
|
||||||
if (regime == null) {
|
|
||||||
this.dialogRef.close(undefined);
|
this.dialogRef.close(undefined);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this.dialogRef.close(`${regime?.prefix}-${billNumber}`);
|
this.dialogRef.close(`${regime.prefix}-${billNumber ?? 0}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { SelectionModel } from '@angular/cdk/collections';
|
||||||
import { Injectable, Injector, computed, inject, signal } from '@angular/core';
|
import { Injectable, Injector, computed, effect, inject, signal } from '@angular/core';
|
||||||
import { toObservable } from '@angular/core/rxjs-interop';
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { filter, take, tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ModifierCategory } from '../core/modifier-category';
|
import { ModifierCategory } from '../core/modifier-category';
|
||||||
import { ProductQuery } from '../core/product-query';
|
import { ProductQuery } from '../core/product-query';
|
||||||
@@ -32,8 +31,8 @@ export class BillService {
|
|||||||
private modifierCategoryService = inject(ModifierCategoryService);
|
private modifierCategoryService = inject(ModifierCategoryService);
|
||||||
private injector = inject(Injector);
|
private injector = inject(Injector);
|
||||||
|
|
||||||
public data = signal<Kot[]>([]);
|
public bill = signal<Bill>(new Bill());
|
||||||
public bill: Bill = new Bill();
|
public data = computed(() => this.bill().kots);
|
||||||
private originalBill: Bill = new Bill();
|
private originalBill: Bill = new Bill();
|
||||||
|
|
||||||
public grossAmount = computed(() =>
|
public grossAmount = computed(() =>
|
||||||
@@ -75,32 +74,29 @@ export class BillService {
|
|||||||
|
|
||||||
public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount());
|
public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount());
|
||||||
public selection = new SelectionModel<string>(true, []);
|
public selection = new SelectionModel<string>(true, []);
|
||||||
private updateTable: boolean;
|
private updateTable = signal<boolean>(true);
|
||||||
private allowDeactivate: boolean;
|
private allowDeactivate = signal<boolean>(false);
|
||||||
|
|
||||||
// To disable Deactivate Guard on navigation after printing bill or kot.
|
// To disable Deactivate Guard on navigation after printing bill or kot.
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.updateTable = true;
|
|
||||||
this.allowDeactivate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
displayBill(): void {
|
|
||||||
this.allowDeactivate = false;
|
|
||||||
this.data.set([...this.bill.kots]);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadData(bill: Bill, updateTable: boolean): void {
|
loadData(bill: Bill, updateTable: boolean): void {
|
||||||
this.updateTable = updateTable;
|
this.updateTable.set(updateTable);
|
||||||
bill.kots.push(new Kot());
|
bill.kots.push(new Kot());
|
||||||
this.bill = bill;
|
this.originalBill = JSON.parse(JSON.stringify(bill));
|
||||||
this.originalBill = JSON.parse(JSON.stringify(this.bill));
|
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
this.displayBill();
|
this.bill.set(bill);
|
||||||
|
this.allowDeactivate.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.bill.set(new Bill());
|
||||||
|
this.originalBill = new Bill();
|
||||||
|
this.selection.clear();
|
||||||
|
this.allowDeactivate.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
k.inventories
|
||||||
.filter((i) => i.sku.id === skuId && i.isHappyHour === happyHour)
|
.filter((i) => i.sku.id === skuId && i.isHappyHour === happyHour)
|
||||||
@@ -112,7 +108,7 @@ export class BillService {
|
|||||||
addOneSku(sku: ProductQuery): void {
|
addOneSku(sku: ProductQuery): void {
|
||||||
const quantity = 1;
|
const quantity = 1;
|
||||||
const discount = 0;
|
const discount = 0;
|
||||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
const newKot = this.bill().kots.find((k) => k.id === undefined) as Kot;
|
||||||
const old = newKot.inventories.find(
|
const old = newKot.inventories.find(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.sku.id === sku.id && x.isHappyHour === sku.hasHappyHour && x.type === (sku.isBundle ? 'bundle' : 'regular'),
|
x.sku.id === sku.id && x.isHappyHour === sku.hasHappyHour && x.type === (sku.isBundle ? 'bundle' : 'regular'),
|
||||||
@@ -155,18 +151,21 @@ export class BillService {
|
|||||||
}
|
}
|
||||||
newKot.inventories.push(item);
|
newKot.inventories.push(item);
|
||||||
const modRes = this.modifierCategoryService.listForSku(signal(sku.id as string));
|
const modRes = this.modifierCategoryService.listForSku(signal(sku.id as string));
|
||||||
toObservable(modRes.value, { injector: this.injector })
|
const effectRef = effect(
|
||||||
.pipe(
|
() => {
|
||||||
filter((result): result is ModifierCategory[] => !!result),
|
const result = modRes.value();
|
||||||
take(1),
|
if (result) {
|
||||||
)
|
if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) {
|
||||||
.subscribe((result) => {
|
this.showModifier(item);
|
||||||
if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) {
|
}
|
||||||
this.showModifier(item);
|
effectRef.destroy();
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
{ injector: this.injector },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
showModifier(item: Inventory): void {
|
showModifier(item: Inventory): void {
|
||||||
@@ -188,7 +187,8 @@ export class BillService {
|
|||||||
if (result !== undefined) {
|
if (result !== undefined) {
|
||||||
item.modifiers = result;
|
item.modifiers = result;
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,8 @@ export class BillService {
|
|||||||
child.quantity += old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0;
|
child.quantity += old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
quantity(item: BillRow, quantity: number): void {
|
quantity(item: BillRow, quantity: number): void {
|
||||||
@@ -211,7 +212,8 @@ export class BillService {
|
|||||||
child.quantity = (old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0) * quantity;
|
child.quantity = (old.sku.bundleItems.find((bi) => bi.id === child.sku.id)?.quantity || 0) * quantity;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtractOne(item: BillRow, canEdit: boolean): void {
|
subtractOne(item: BillRow, canEdit: boolean): void {
|
||||||
@@ -230,14 +232,16 @@ export class BillService {
|
|||||||
} else if (old.quantity === 0) {
|
} else if (old.quantity === 0) {
|
||||||
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem(item: BillRow): void {
|
removeItem(item: BillRow): void {
|
||||||
const newKot = item.kot as Kot;
|
const newKot = item.kot as Kot;
|
||||||
const old = item.inv as Inventory;
|
const old = item.inv as Inventory;
|
||||||
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier(item: BillRow): void {
|
modifier(item: BillRow): void {
|
||||||
@@ -246,7 +250,7 @@ export class BillService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
discount(discounts: { id: string; name: string; discount: number }[]): void {
|
discount(discounts: { id: string; name: string; discount: number }[]): void {
|
||||||
for (const kot of this.bill.kots) {
|
for (const kot of this.bill().kots) {
|
||||||
const noDiscount = kot.inventories.filter((x) => x.isHappyHour).map((x) => x.sku.id as string);
|
const noDiscount = kot.inventories.filter((x) => x.isHappyHour).map((x) => x.sku.id as string);
|
||||||
for (const inventory of kot.inventories) {
|
for (const inventory of kot.inventories) {
|
||||||
if (noDiscount.indexOf(inventory.sku.id as string) !== -1) {
|
if (noDiscount.indexOf(inventory.sku.id as string) !== -1) {
|
||||||
@@ -259,7 +263,8 @@ export class BillService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.displayBill();
|
this.allowDeactivate.set(false);
|
||||||
|
this.bill.update((b) => new Bill({ ...b, kots: [...b.kots] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
isBillDiffent(bill: Bill, guestBookId: string | null): boolean {
|
isBillDiffent(bill: Bill, guestBookId: string | null): boolean {
|
||||||
@@ -282,7 +287,7 @@ export class BillService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printKot(guestBookId: string | null): Observable<boolean> {
|
printKot(guestBookId: string | null): Observable<boolean> {
|
||||||
const item = JSON.parse(JSON.stringify(this.bill));
|
const item = JSON.parse(JSON.stringify(this.bill()));
|
||||||
if (!this.isBillDiffent(item, guestBookId)) {
|
if (!this.isBillDiffent(item, guestBookId)) {
|
||||||
return throwError(() => Error('Cannot print a blank KOT\nPlease add some products!'));
|
return throwError(() => Error('Cannot print a blank KOT\nPlease add some products!'));
|
||||||
}
|
}
|
||||||
@@ -290,12 +295,12 @@ export class BillService {
|
|||||||
return throwError(() => Error('Happy hour products are not balanced.'));
|
return throwError(() => Error('Happy hour products are not balanced.'));
|
||||||
}
|
}
|
||||||
return this.ser
|
return this.ser
|
||||||
.saveOrUpdate(item, VoucherType.Kot, guestBookId, this.updateTable)
|
.saveOrUpdate(item, VoucherType.Kot, guestBookId, this.updateTable())
|
||||||
.pipe(tap(() => (this.allowDeactivate = true)));
|
.pipe(tap(() => this.allowDeactivate.set(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
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((p: number, k: Kot) => p + k.inventories.filter((i) => i.quantity !== 0).length, 0);
|
const skus = item.kots.reduce((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!'));
|
||||||
@@ -304,41 +309,41 @@ export class BillService {
|
|||||||
return throwError(() => Error('Happy hour products are not balanced.'));
|
return throwError(() => Error('Happy hour products are not balanced.'));
|
||||||
}
|
}
|
||||||
return this.ser
|
return this.ser
|
||||||
.saveOrUpdate(item, voucherType, guestBookId, this.updateTable)
|
.saveOrUpdate(item, voucherType, guestBookId, this.updateTable())
|
||||||
.pipe(tap(() => (this.allowDeactivate = true)));
|
.pipe(tap(() => this.allowDeactivate.set(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
receivePayment(value: { choices: ReceivePaymentItem[]; reason: string }): Observable<boolean> {
|
receivePayment(value: { choices: ReceivePaymentItem[]; reason: string }): Observable<boolean> {
|
||||||
return this.ser.receivePayment(this.bill.id as string, value.choices, value.reason, this.updateTable);
|
return this.ser.receivePayment(this.bill().id as string, value.choices, value.reason, this.updateTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTable(table: Table): Observable<boolean> {
|
moveTable(table: Table): Observable<boolean> {
|
||||||
return this.ser.moveTable(this.bill.id as string, table);
|
return this.ser.moveTable(this.bill().id as string, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeTable(table: Table): Observable<boolean> {
|
mergeTable(table: Table): Observable<boolean> {
|
||||||
return this.ser.mergeTable(this.bill.id as string, table);
|
return this.ser.mergeTable(this.bill().id as string, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveKot(kotId: string, table: Table): Observable<boolean> {
|
moveKot(kotId: string, table: Table): Observable<boolean> {
|
||||||
return this.ser.moveKotToNewTable(this.bill.id as string, kotId, table);
|
return this.ser.moveKotToNewTable(this.bill().id as string, kotId, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeKot(kotId: string, table: Table): Observable<boolean> {
|
mergeKot(kotId: string, table: Table): Observable<boolean> {
|
||||||
return this.ser.mergeKotWithOldBill(this.bill.id as string, kotId, table);
|
return this.ser.mergeKotWithOldBill(this.bill().id as string, kotId, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelBill(reason: string): Observable<boolean> {
|
cancelBill(reason: string): Observable<boolean> {
|
||||||
return this.ser.cancelBill(this.bill.id as string, reason, this.updateTable);
|
return this.ser.cancelBill(this.bill().id as string, reason, this.updateTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
splitBill(inventories: string[], table: Table): Observable<boolean> {
|
splitBill(inventories: string[], table: Table): Observable<boolean> {
|
||||||
return this.ser.splitBill(this.bill.id as string, inventories, table, this.updateTable);
|
return this.ser.splitBill(this.bill().id as string, inventories, table, this.updateTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getInventories(saleCategories: string[]): { move: string[]; keep: string[] } {
|
public getInventories(saleCategories: string[]): { move: string[]; keep: string[] } {
|
||||||
const data: { move: string[]; keep: string[] } = { move: [], keep: [] };
|
const data: { move: string[]; keep: string[] } = { move: [], keep: [] };
|
||||||
for (const kot of this.bill.kots) {
|
for (const kot of this.bill().kots) {
|
||||||
for (const inv of kot.inventories) {
|
for (const inv of kot.inventories) {
|
||||||
if (saleCategories.indexOf(inv.sku.saleCategory?.id as string) === -1) {
|
if (saleCategories.indexOf(inv.sku.saleCategory?.id as string) === -1) {
|
||||||
data.keep.push(inv.id as string);
|
data.keep.push(inv.id as string);
|
||||||
@@ -350,57 +355,63 @@ export class BillService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private happyHourItemsBalanced(): boolean {
|
private happyHourItemsBalanced = computed<boolean>(() => {
|
||||||
return this.bill.kots.every((kot) => {
|
return this.bill().kots.every((kot) => {
|
||||||
const happyHourItems = kot.inventories
|
const happyHourQtyMap = new Map<string, number>();
|
||||||
.filter((x) => x.isHappyHour)
|
const regularQtyMap = new Map<string, number>();
|
||||||
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }))
|
|
||||||
.sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
||||||
const happyHourIds = happyHourItems.map((x) => x.id);
|
|
||||||
const rest = kot.inventories
|
|
||||||
.filter((x) => !x.isHappyHour && happyHourIds.indexOf(x.sku.id as string) !== -1)
|
|
||||||
.map((x) => ({ id: x.sku.id as string, quantity: x.quantity }))
|
|
||||||
.sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
||||||
if (happyHourIds.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
happyHourItems.length === rest.length &&
|
|
||||||
happyHourItems.every((v, i) => v.id === rest[i].id && v.quantity === rest[i].quantity)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private regularItemsMoreThanHappyHour(): boolean {
|
for (const item of kot.inventories) {
|
||||||
|
const id = item.sku.id as string;
|
||||||
|
if (item.isHappyHour) {
|
||||||
|
happyHourQtyMap.set(id, (happyHourQtyMap.get(id) ?? 0) + item.quantity);
|
||||||
|
} else {
|
||||||
|
regularQtyMap.set(id, (regularQtyMap.get(id) ?? 0) + item.quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [id, hhQty] of happyHourQtyMap.entries()) {
|
||||||
|
if (regularQtyMap.get(id) !== hhQty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
private regularItemsMoreThanHappyHour = computed<boolean>(() => {
|
||||||
// This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4
|
// This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4
|
||||||
// This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check
|
// This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check
|
||||||
|
|
||||||
const inventories = this.bill.kots
|
const happyHourQtyMap = new Map<string, number>();
|
||||||
.flatMap((kot) => kot.inventories)
|
const regularQtyMap = new Map<string, number>();
|
||||||
.reduce((acc: { id: string; quantity: number; isHappyHour: boolean }[], curr) => {
|
|
||||||
const existing = acc.find((x) => x.id === curr.sku.id && x.isHappyHour === curr.isHappyHour);
|
for (const kot of this.bill().kots) {
|
||||||
if (existing) {
|
for (const item of kot.inventories) {
|
||||||
existing.quantity += curr.quantity;
|
const id = item.sku.id as string;
|
||||||
|
if (item.isHappyHour) {
|
||||||
|
happyHourQtyMap.set(id, (happyHourQtyMap.get(id) ?? 0) + item.quantity);
|
||||||
} else {
|
} else {
|
||||||
acc.push({ id: curr.sku.id as string, quantity: curr.quantity, isHappyHour: curr.isHappyHour });
|
regularQtyMap.set(id, (regularQtyMap.get(id) ?? 0) + item.quantity);
|
||||||
}
|
}
|
||||||
return acc;
|
}
|
||||||
}, [])
|
}
|
||||||
.sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
||||||
const happyHourItems = inventories.filter((x) => x.isHappyHour);
|
for (const [id, hhQty] of happyHourQtyMap.entries()) {
|
||||||
const happyHourIds = happyHourItems.map((x) => x.id);
|
const regQty = regularQtyMap.get(id) ?? 0;
|
||||||
const rest = inventories.filter((x) => !x.isHappyHour && happyHourIds.indexOf(x.id as string) !== -1);
|
if (regQty < hhQty) {
|
||||||
return (
|
return false;
|
||||||
happyHourItems.length === rest.length &&
|
}
|
||||||
happyHourItems.every((hh, index) => hh.id === rest[index].id && hh.quantity <= rest[index].quantity)
|
}
|
||||||
);
|
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
public canDeactivate(): boolean {
|
public canDeactivate(): boolean {
|
||||||
if (this.allowDeactivate) {
|
if (this.allowDeactivate()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
const newKot = this.bill().kots.find((k) => k.id === undefined) as Kot;
|
||||||
return newKot.inventories.length === 0;
|
return newKot.inventories.length === 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="bill-no-details">
|
<ng-container matColumnDef="bill-no-details">
|
||||||
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align"
|
<mat-header-cell *matHeaderCellDef class="deep-purple-200 bold right-align"
|
||||||
>{{ bs.bill.billId }} / K-{{ bs.bill.kotId }}</mat-header-cell
|
>{{ bs.bill().billId }} / K-{{ bs.bill().kotId }}</mat-header-cell
|
||||||
>
|
>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="time-title">
|
<ng-container matColumnDef="time-title">
|
||||||
@@ -15,9 +15,9 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="time-details">
|
<ng-container matColumnDef="time-details">
|
||||||
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align"
|
<mat-header-cell *matHeaderCellDef class="deep-purple-100 bold right-align"
|
||||||
><span [matTooltip]="bs.bill.dateTip">{{ bs.bill.date }}</span
|
><span [matTooltip]="bs.bill().dateTip">{{ bs.bill().date }}</span
|
||||||
> / <span [matTooltip]="bs.bill.creationDateTip">{{ bs.bill.creationDate }}</span
|
> / <span [matTooltip]="bs.bill().creationDateTip">{{ bs.bill().creationDate }}</span
|
||||||
> / <span [matTooltip]="bs.bill.lastEditDateTip">{{ bs.bill.lastEditDate }}</span></mat-header-cell
|
> / <span [matTooltip]="bs.bill().lastEditDateTip">{{ bs.bill().lastEditDate }}</span></mat-header-cell
|
||||||
>
|
>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="table-title">
|
<ng-container matColumnDef="table-title">
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="table-details">
|
<ng-container matColumnDef="table-details">
|
||||||
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align"
|
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align"
|
||||||
><button>Table: {{ bs.bill.table.name }}</button> /
|
><button>Table: {{ bs.bill().table.name }}</button> /
|
||||||
<button type="button" mat-button (click)="choosePax()">{{ bs.bill.pax }} Pax</button> /
|
<button type="button" mat-button (click)="choosePax()">{{ bs.bill().pax }} Pax</button> /
|
||||||
<button type="button" mat-button (click)="chooseCustomer()">
|
<button type="button" mat-button (click)="chooseCustomer()">
|
||||||
{{ bs.bill.customer?.name ?? 'Customer' }}
|
{{ bs.bill().customer?.name ?? 'Customer' }}
|
||||||
</button></mat-header-cell
|
</button></mat-header-cell
|
||||||
>
|
>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CommonModule, CurrencyPipe } from '@angular/common';
|
import { CommonModule, CurrencyPipe } from '@angular/common';
|
||||||
import { Component, OnInit, inject, computed, effect, input } from '@angular/core';
|
import { Component, OnDestroy, OnInit, Signal, computed, effect, inject, input } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@@ -7,7 +7,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
|
import { Router, RouterOutlet } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { map, switchMap } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
@@ -44,8 +44,7 @@ import { VoucherService } from './voucher.service';
|
|||||||
RouterOutlet,
|
RouterOutlet,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class BillsComponent implements OnInit {
|
export class BillsComponent implements OnInit, OnDestroy {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
@@ -112,8 +111,12 @@ export class BillsComponent implements OnInit {
|
|||||||
this.getPax();
|
this.getPax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.bs.reset();
|
||||||
|
}
|
||||||
|
|
||||||
getPax(): void {
|
getPax(): void {
|
||||||
if (this.bs.bill.id || this.bs.bill.customer) {
|
if (this.bs.bill().id || this.bs.bill().customer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.choosePax();
|
this.choosePax();
|
||||||
@@ -122,14 +125,14 @@ export class BillsComponent implements OnInit {
|
|||||||
choosePax(): void {
|
choosePax(): void {
|
||||||
const dialogRef = this.dialog.open(PaxComponent, {
|
const dialogRef = this.dialog.open(PaxComponent, {
|
||||||
// width: '750px',
|
// width: '750px',
|
||||||
data: this.bs.bill.pax,
|
data: this.bs.bill().pax,
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe((result: boolean | number) => {
|
dialogRef.afterClosed().subscribe((result: boolean | number) => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.bs.bill.pax = result as number;
|
this.bs.bill.update((b) => new Bill({ ...b, pax: result as number }));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,14 +140,14 @@ export class BillsComponent implements OnInit {
|
|||||||
const dialogRef = this.dialog.open(ChooseCustomerComponent, {
|
const dialogRef = this.dialog.open(ChooseCustomerComponent, {
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
width: '50%',
|
width: '50%',
|
||||||
data: this.bs.bill.customer,
|
data: this.bs.bill().customer,
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe((result: boolean | Customer) => {
|
dialogRef.afterClosed().subscribe((result: boolean | Customer) => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.bs.bill.customer = null;
|
this.bs.bill.update((b) => new Bill({ ...b, customer: null }));
|
||||||
} else {
|
} else {
|
||||||
this.bs.bill.customer = result as Customer;
|
this.bs.bill.update((b) => new Bill({ ...b, customer: result as Customer }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -248,7 +251,7 @@ export class BillsComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
chooseTable(allowMerge: boolean): Observable<Table> {
|
chooseTable(allowMerge: Signal<boolean>): Observable<Table> {
|
||||||
return this.dialog
|
return this.dialog
|
||||||
.open(TablesDialogComponent, {
|
.open(TablesDialogComponent, {
|
||||||
// width: '750px',
|
// width: '750px',
|
||||||
@@ -269,15 +272,15 @@ export class BillsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
moveKot(kot: BillRow): void {
|
moveKot(kot: BillRow): void {
|
||||||
const canMergeTables = this.auth.allowed('merge-tables');
|
const canMergeTables = computed(() => this.auth.allowed('merge-tables'));
|
||||||
this.chooseTable(canMergeTables)
|
this.chooseTable(canMergeTables)
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap((table: Table) => this.confirmMoveKotDialog(table)),
|
switchMap((table: Table) => this.confirmMoveKotDialog(table)),
|
||||||
switchMap((table: Table) => {
|
switchMap((table: Table) => {
|
||||||
if (this.bs.bill.kots.length === 1 && table.status) {
|
if (this.bs.bill().kots.length === 1 && table.status) {
|
||||||
return this.bs.mergeTable(table);
|
return this.bs.mergeTable(table);
|
||||||
}
|
}
|
||||||
if (this.bs.bill.kots.length === 1 && !table.status) {
|
if (this.bs.bill().kots.length === 1 && !table.status) {
|
||||||
return this.bs.moveTable(table);
|
return this.bs.moveTable(table);
|
||||||
}
|
}
|
||||||
if (table.status) {
|
if (table.status) {
|
||||||
@@ -302,7 +305,7 @@ export class BillsComponent implements OnInit {
|
|||||||
if (!isPrinted) {
|
if (!isPrinted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType === VoucherType.Void) {
|
if (this.bs.bill().voucherType === VoucherType.Void) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!this.auth.allowed('edit-printed-product')) {
|
if (!this.auth.allowed('edit-printed-product')) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, inject, computed, signal, input } from '@angular/core';
|
import { Component, Signal, computed, inject, input, signal } from '@angular/core';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@@ -47,18 +47,18 @@ export class SalesHomeComponent {
|
|||||||
return (x || []).map((y: SaleCategory) => ({ id: y.id, name: y.name, selected: false }));
|
return (x || []).map((y: SaleCategory) => ({ id: y.id, name: y.name, selected: false }));
|
||||||
});
|
});
|
||||||
|
|
||||||
printKotAllowed(): boolean {
|
printKotAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('print-kot')) {
|
if (!this.auth.allowed('print-kot')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType !== VoucherType.Kot) {
|
if (this.bs.bill().voucherType !== VoucherType.Kot) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
printKot() {
|
printKot() {
|
||||||
if (!this.printKotAllowed()) {
|
if (!this.printKotAllowed()) {
|
||||||
@@ -75,15 +75,15 @@ export class SalesHomeComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
discountAllowed(): boolean {
|
discountAllowed = computed<boolean>(() => {
|
||||||
return this.auth.allowed('discount');
|
return this.auth.allowed('discount');
|
||||||
}
|
});
|
||||||
|
|
||||||
showDiscount(): Observable<boolean | { id: string; name: string; discount: number }[]> {
|
showDiscount(): Observable<boolean | { id: string; name: string; discount: number }[]> {
|
||||||
if (this.discountAllowed()) {
|
if (this.discountAllowed()) {
|
||||||
const dialogRef = this.dialog.open(DiscountComponent, {
|
const dialogRef = this.dialog.open(DiscountComponent, {
|
||||||
// width: '750px',
|
// width: '750px',
|
||||||
data: this.customerDiscountsService.list(signal(this.bs.bill.customer?.id)),
|
data: this.customerDiscountsService.list(signal(this.bs.bill().customer?.id)),
|
||||||
});
|
});
|
||||||
return dialogRef.afterClosed();
|
return dialogRef.afterClosed();
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,8 @@ export class SalesHomeComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
billTypeDialog() {
|
billTypeDialog() {
|
||||||
if (this.bs.bill.voucherType !== VoucherType.Kot) {
|
if (this.bs.bill().voucherType !== VoucherType.Kot) {
|
||||||
return observableOf(this.bs.bill.voucherType);
|
return observableOf(this.bs.bill().voucherType);
|
||||||
}
|
}
|
||||||
return this.dialog.open(BillTypeComponent).afterClosed();
|
return this.dialog.open(BillTypeComponent).afterClosed();
|
||||||
}
|
}
|
||||||
@@ -125,21 +125,21 @@ export class SalesHomeComponent {
|
|||||||
.pipe(map((x: boolean) => (x ? reason : x)));
|
.pipe(map((x: boolean) => (x ? reason : x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
printBillAllowed(): boolean {
|
printBillAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('print-bill')) {
|
if (!this.auth.allowed('print-bill')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType !== VoucherType.Kot && !this.auth.allowed('edit-printed-bill')) {
|
if (this.bs.bill().voucherType !== VoucherType.Kot && !this.auth.allowed('edit-printed-bill')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType === VoucherType.Void) {
|
if (this.bs.bill().voucherType === VoucherType.Void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
printBill() {
|
printBill() {
|
||||||
if (!this.printBillAllowed()) {
|
if (!this.printBillAllowed()) {
|
||||||
@@ -174,28 +174,28 @@ export class SalesHomeComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
receivePaymentAllowed(): boolean {
|
receivePaymentAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('settle-bill')) {
|
if (!this.auth.allowed('settle-bill')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType === VoucherType.Kot) {
|
if (this.bs.bill().voucherType === VoucherType.Kot) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.bs.bill.voucherType === VoucherType.Void) {
|
if (this.bs.bill().voucherType === VoucherType.Void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
receivePayment() {
|
receivePayment() {
|
||||||
if (!this.receivePaymentAllowed()) {
|
if (!this.receivePaymentAllowed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const amount = this.bs.amount();
|
const amount = this.bs.amount();
|
||||||
const type = this.bs.bill.voucherType;
|
const type = this.bs.bill().voucherType;
|
||||||
this.dialog
|
this.dialog
|
||||||
.open(ReceivePaymentComponent, {
|
.open(ReceivePaymentComponent, {
|
||||||
data: {
|
data: {
|
||||||
@@ -223,21 +223,21 @@ export class SalesHomeComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTableAllowed(): boolean {
|
moveTableAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('move-table') && !this.auth.allowed('merge-tables')) {
|
if (!this.auth.allowed('move-table') && !this.auth.allowed('merge-tables')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
moveTable() {
|
moveTable() {
|
||||||
if (!this.moveTableAllowed()) {
|
if (!this.moveTableAllowed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const canMergeTables = this.auth.allowed('merge-tables');
|
const canMergeTables = computed(() => this.auth.allowed('merge-tables'));
|
||||||
this.showChooseTableDialog(canMergeTables)
|
this.showChooseTableDialog(canMergeTables)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((x) => {
|
tap((x) => {
|
||||||
@@ -266,15 +266,15 @@ export class SalesHomeComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelBillAllowed(): boolean {
|
cancelBillAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('void-bill')) {
|
if (!this.auth.allowed('void-bill')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
cancelBill() {
|
cancelBill() {
|
||||||
if (!this.cancelBillAllowed()) {
|
if (!this.cancelBillAllowed()) {
|
||||||
@@ -322,15 +322,15 @@ export class SalesHomeComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
splitBillAllowed(): boolean {
|
splitBillAllowed = computed<boolean>(() => {
|
||||||
if (!this.auth.allowed('split-bill')) {
|
if (!this.auth.allowed('split-bill')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.bs.bill.id) {
|
if (!this.bs.bill().id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
showBillSplitChoices(): Observable<{ id: string; name: string; selected: boolean }[] | undefined | false> {
|
showBillSplitChoices(): Observable<{ id: string; name: string; selected: boolean }[] | undefined | false> {
|
||||||
return this.dialog
|
return this.dialog
|
||||||
@@ -340,7 +340,7 @@ export class SalesHomeComponent {
|
|||||||
.afterClosed();
|
.afterClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
showChooseTableDialog(canChooseRunning: boolean): Observable<Table | undefined | null> {
|
showChooseTableDialog(canChooseRunning: Signal<boolean>): Observable<Table | undefined | null> {
|
||||||
return this.dialog
|
return this.dialog
|
||||||
.open(TablesDialogComponent, {
|
.open(TablesDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
@@ -360,7 +360,7 @@ export class SalesHomeComponent {
|
|||||||
obs
|
obs
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((x) => (inventories = x)),
|
tap((x) => (inventories = x)),
|
||||||
switchMap(() => this.showChooseTableDialog(false)),
|
switchMap(() => this.showChooseTableDialog(signal(false))),
|
||||||
tap((x) => {
|
tap((x) => {
|
||||||
if (!x) {
|
if (!x) {
|
||||||
throw new Error('Please choose a table');
|
throw new Error('Please choose a table');
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<h2 mat-dialog-title>Pax</h2>
|
<h2 mat-dialog-title>Pax</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<form>
|
<form (submit)="$event.preventDefault(); accept()">
|
||||||
<div class="row-container">
|
<div class="row-container">
|
||||||
<mat-form-field class="flex-auto">
|
<mat-form-field class="flex-auto">
|
||||||
<mat-label>Pax</mat-label>
|
<mat-label>Pax</mat-label>
|
||||||
@@ -18,6 +18,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button [mat-dialog-close]="false">Cancel</button>
|
<button type="button" mat-button [mat-dialog-close]="false">Cancel</button>
|
||||||
<button type="button" mat-button (click)="accept()" color="primary">Ok</button>
|
<button type="button" mat-button (click)="accept()" color="primary">Ok</button>
|
||||||
</mat-dialog-actions>
|
</mat-dialog-actions>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
||||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { form, FormField } from '@angular/forms/signals';
|
import { form, FormField } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||||
@@ -16,27 +16,17 @@ export interface PaxFormData {
|
|||||||
styleUrls: ['./pax.component.css'],
|
styleUrls: ['./pax.component.css'],
|
||||||
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class PaxComponent implements OnInit {
|
export class PaxComponent {
|
||||||
data = inject(MAT_DIALOG_DATA);
|
private data = inject<number | null>(MAT_DIALOG_DATA, { optional: true });
|
||||||
dialogRef = inject<MatDialogRef<PaxComponent>>(MatDialogRef);
|
private dialogRef = inject<MatDialogRef<PaxComponent>>(MatDialogRef);
|
||||||
|
|
||||||
formModel = signal<PaxFormData>({
|
formModel = signal<PaxFormData>({
|
||||||
pax: null,
|
pax: this.data ?? 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// Create form
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.formModel.set({
|
|
||||||
pax: this.data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
accept(): void {
|
accept(): void {
|
||||||
const pax = this.formModel().pax ?? 0;
|
this.dialogRef.close(this.formModel().pax ?? 0);
|
||||||
this.dialogRef.close(pax);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
import { CdkScrollableModule } from '@angular/cdk/scrolling';
|
||||||
import { Component, OnInit, inject, signal } from '@angular/core';
|
import { Component, inject, signal } from '@angular/core';
|
||||||
import { form, FormField } from '@angular/forms/signals';
|
import { form, FormField } from '@angular/forms/signals';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||||
@@ -18,26 +18,17 @@ export interface QuantityFormData {
|
|||||||
styleUrls: ['./quantity.component.css'],
|
styleUrls: ['./quantity.component.css'],
|
||||||
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [CdkScrollableModule, MatButtonModule, MatDialogModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class QuantityComponent implements OnInit {
|
export class QuantityComponent {
|
||||||
data = inject(MAT_DIALOG_DATA);
|
private data = inject<unknown>(MAT_DIALOG_DATA, { optional: true });
|
||||||
private math = inject(MathService);
|
private math = inject(MathService);
|
||||||
dialogRef = inject<MatDialogRef<QuantityComponent>>(MatDialogRef);
|
private dialogRef = inject<MatDialogRef<QuantityComponent>>(MatDialogRef);
|
||||||
|
|
||||||
formModel = signal<QuantityFormData>({
|
formModel = signal<QuantityFormData>({
|
||||||
quantity: '',
|
quantity: `${this.data ?? ''}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// Create form
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.formModel.set({
|
|
||||||
quantity: `${this.data}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
accept(): void {
|
accept(): void {
|
||||||
const quantity = this.math.parseAmount(this.formModel().quantity ?? '');
|
const quantity = this.math.parseAmount(this.formModel().quantity ?? '');
|
||||||
this.dialogRef.close(quantity);
|
this.dialogRef.close(quantity);
|
||||||
|
|||||||
@@ -26,32 +26,25 @@ export interface ReasonFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ReasonComponent {
|
export class ReasonComponent {
|
||||||
dialogRef = inject<MatDialogRef<ReasonComponent>>(MatDialogRef);
|
private dialogRef = inject<MatDialogRef<ReasonComponent>>(MatDialogRef);
|
||||||
private data = inject<{
|
private data = inject<{
|
||||||
title: string;
|
title: string;
|
||||||
reasons: string[];
|
reasons: string[];
|
||||||
}>(MAT_DIALOG_DATA);
|
}>(MAT_DIALOG_DATA);
|
||||||
|
|
||||||
|
title = this.data.title;
|
||||||
|
reasons = this.data.reasons ?? [];
|
||||||
|
dataSource = computed(() => this.reasons);
|
||||||
|
displayedColumns = ['reason'];
|
||||||
|
selected = '';
|
||||||
|
|
||||||
formModel = signal<ReasonFormData>({
|
formModel = signal<ReasonFormData>({
|
||||||
son: '',
|
son: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
dataSource = computed(() => this.reasons);
|
select(reason: string): boolean {
|
||||||
title: string;
|
|
||||||
selected = '';
|
|
||||||
reasons: string[];
|
|
||||||
displayedColumns = ['reason'];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
const data = this.data;
|
|
||||||
|
|
||||||
this.reasons = data.reasons ?? [];
|
|
||||||
this.title = data.title;
|
|
||||||
}
|
|
||||||
|
|
||||||
select(reason: string) {
|
|
||||||
this.selected = reason.trim();
|
this.selected = reason.trim();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { MatCardModule } from '@angular/material/card';
|
|||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router';
|
import { NavigationExtras, Router } from '@angular/router';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Table } from '../../core/table';
|
import { Table } from '../../core/table';
|
||||||
@@ -23,7 +23,6 @@ export class RunningTablesComponent {
|
|||||||
private regimeService = inject(RegimeService);
|
private regimeService = inject(RegimeService);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
regimesResource = this.regimeService.list();
|
regimesResource = this.regimeService.list();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { MatInputModule } from '@angular/material/input';
|
|||||||
import { MatSelectChange, MatSelectModule } from '@angular/material/select';
|
import { MatSelectChange, 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Printer } from '../core/printer';
|
import { Printer } from '../core/printer';
|
||||||
import { SectionPrinter } from '../core/section-printer';
|
import { SectionPrinter } from '../core/section-printer';
|
||||||
@@ -45,7 +45,6 @@ export interface SectionPrinterFormData {
|
|||||||
export class SectionPrinterComponent {
|
export class SectionPrinterComponent {
|
||||||
private printerService = inject(PrinterService);
|
private printerService = inject(PrinterService);
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Section } from '../../core/section';
|
import { Section } from '../../core/section';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -22,7 +22,6 @@ export interface SectionDetailFormData {
|
|||||||
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
imports: [MatButtonModule, MatFormFieldModule, MatInputModule, FormField],
|
||||||
})
|
})
|
||||||
export class SectionDetailComponent {
|
export class SectionDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { SectionService } from '../section.service';
|
import { SectionService } from '../section.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,7 +13,6 @@ import { SectionService } from '../section.service';
|
|||||||
})
|
})
|
||||||
export class SectionListComponent {
|
export class SectionListComponent {
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.sectionService.list();
|
listResource = this.sectionService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -49,5 +49,5 @@
|
|||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>Backend: v{{ auth.user?.ver }} / Frontend: v{{ version }}</p>
|
<p>Backend: v{{ auth.user()?.ver }} / Frontend: v{{ version }}</p>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -3,13 +3,11 @@ import { form, FormField } from '@angular/forms/signals';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { environment } from '../app.environment';
|
import { environment } from '../app.environment';
|
||||||
@@ -33,9 +31,6 @@ import { SettingsService } from './settings.service';
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SettingsComponent {
|
export class SettingsComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
|
||||||
private dialog = inject(MatDialog);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
auth = inject(AuthService);
|
auth = inject(AuthService);
|
||||||
private ser = inject(SettingsService);
|
private ser = inject(SettingsService);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { ReportingLevel } from '../../core/reporting-level';
|
import { ReportingLevel } from '../../core/reporting-level';
|
||||||
import { SettleOption } from '../../core/settle-option';
|
import { SettleOption } from '../../core/settle-option';
|
||||||
@@ -38,7 +38,6 @@ export interface SettleOptionDetailFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SettleOptionDetailComponent {
|
export class SettleOptionDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Component, inject, computed } from '@angular/core';
|
import { Component, inject, computed } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { ReportingLevel } from '../../core/reporting-level';
|
import { ReportingLevel } from '../../core/reporting-level';
|
||||||
import { VoucherType } from '../../sales/bills/voucher-type';
|
import { VoucherType } from '../../sales/bills/voucher-type';
|
||||||
@@ -15,9 +14,6 @@ import { SettleOptionService } from '../settle-option.service';
|
|||||||
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
|
imports: [MatButtonModule, MatIconModule, MatTableModule, RouterLink],
|
||||||
})
|
})
|
||||||
export class SettleOptionListComponent {
|
export class SettleOptionListComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
|
||||||
private ser = inject(SettleOptionService);
|
private ser = inject(SettleOptionService);
|
||||||
listResource = this.ser.list();
|
listResource = this.ser.list();
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { Section } from '../../core/section';
|
import { Section } from '../../core/section';
|
||||||
import { Table } from '../../core/table';
|
import { Table } from '../../core/table';
|
||||||
@@ -39,7 +39,6 @@ export interface TableDetailFormData {
|
|||||||
})
|
})
|
||||||
export class TableDetailComponent {
|
export class TableDetailComponent {
|
||||||
private sectionService = inject(SectionService);
|
private sectionService = inject(SectionService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
import { Table } from '../../core/table';
|
import { Table } from '../../core/table';
|
||||||
@@ -17,8 +17,6 @@ import { TableService } from '../table.service';
|
|||||||
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink, MatToolbarModule],
|
imports: [DragDropModule, MatButtonModule, MatIconModule, MatTableModule, RouterLink, MatToolbarModule],
|
||||||
})
|
})
|
||||||
export class TableListComponent {
|
export class TableListComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private ser = inject(TableService);
|
private ser = inject(TableService);
|
||||||
listResource = this.ser.list();
|
listResource = this.ser.list();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { ToCsvService } from '../shared/to-csv.service';
|
import { ToCsvService } from '../shared/to-csv.service';
|
||||||
@@ -37,7 +37,6 @@ export interface TaxReportFormData {
|
|||||||
})
|
})
|
||||||
export class TaxReportComponent {
|
export class TaxReportComponent {
|
||||||
private taxReportService = inject(TaxReportService);
|
private taxReportService = inject(TaxReportService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
startDate = input(null, { transform: (v: string | null | undefined) => v ?? null });
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
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 { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { round } from 'mathjs';
|
import { round } from 'mathjs';
|
||||||
|
|
||||||
import { Regime } from '../../core/regime';
|
import { Regime } from '../../core/regime';
|
||||||
@@ -30,7 +30,6 @@ export interface TaxDetailFormData {
|
|||||||
})
|
})
|
||||||
export class TaxDetailComponent {
|
export class TaxDetailComponent {
|
||||||
private regimeService = inject(RegimeService);
|
private regimeService = inject(RegimeService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Component, inject, computed } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { TaxService } from '../tax.service';
|
import { TaxService } from '../tax.service';
|
||||||
@Component({
|
@Component({
|
||||||
@@ -14,7 +14,6 @@ import { TaxService } from '../tax.service';
|
|||||||
})
|
})
|
||||||
export class TaxListComponent {
|
export class TaxListComponent {
|
||||||
private taxService = inject(TaxService);
|
private taxService = inject(TaxService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.taxService.list();
|
listResource = this.taxService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
+1
-10
@@ -13,7 +13,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { MenuCategory } from '../../core/menu-category';
|
import { MenuCategory } from '../../core/menu-category';
|
||||||
@@ -67,7 +67,6 @@ export interface TemporalSkuFormData {
|
|||||||
export class TemporalProductDetailComponent {
|
export class TemporalProductDetailComponent {
|
||||||
private menuCategoryService = inject(MenuCategoryService);
|
private menuCategoryService = inject(MenuCategoryService);
|
||||||
private saleCategoryService = inject(SaleCategoryService);
|
private saleCategoryService = inject(SaleCategoryService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
@@ -156,14 +155,6 @@ export class TemporalProductDetailComponent {
|
|||||||
return !d ? null : moment(d).format('DD-MMM-YYYY');
|
return !d ? null : moment(d).format('DD-MMM-YYYY');
|
||||||
}
|
}
|
||||||
|
|
||||||
// showItem(item: TemporalProduct) {
|
|
||||||
// this.item = item;
|
|
||||||
// this.selectedProduct = this.item.products[0];
|
|
||||||
// this.selectedSku = this.item.skus[0];
|
|
||||||
|
|
||||||
//
|
|
||||||
// // }
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
afterNextRender(() => {
|
afterNextRender(() => {
|
||||||
this.productForm().focusBoundControl();
|
this.productForm().focusBoundControl();
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-auto basis-30">
|
<mat-form-field class="flex-auto basis-30">
|
||||||
<mat-label>Menu Category</mat-label>
|
<mat-label>Menu Category</mat-label>
|
||||||
<mat-select [formField]="form.menuCategory" (selectionChange)="filterMcOn($event.value)">
|
<mat-select [formField]="form.menuCategory">
|
||||||
<mat-option>-- All Products --</mat-option>
|
<mat-option>-- All Products --</mat-option>
|
||||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="flex-auto basis-30">
|
<mat-form-field class="flex-auto basis-30">
|
||||||
<mat-label>Sale Category</mat-label>
|
<mat-label>Sale Category</mat-label>
|
||||||
<mat-select [formField]="form.saleCategory" (selectionChange)="filterScOn($event.value)">
|
<mat-select [formField]="form.saleCategory">
|
||||||
<mat-option>-- All Products --</mat-option>
|
<mat-option>-- All Products --</mat-option>
|
||||||
@for (mc of saleCategoriesResource.value(); track mc) {
|
@for (mc of saleCategoriesResource.value(); track mc) {
|
||||||
<mat-option [value]="mc.id">
|
<mat-option [value]="mc.id">
|
||||||
|
|||||||
+3
-12
@@ -25,7 +25,6 @@ export interface TemporalProductListFormData {
|
|||||||
styleUrls: ['./temporal-product-list.component.css'],
|
styleUrls: ['./temporal-product-list.component.css'],
|
||||||
imports: [
|
imports: [
|
||||||
CurrencyPipe,
|
CurrencyPipe,
|
||||||
// DecimalPipe,
|
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
@@ -45,9 +44,6 @@ export class TemporalProductListComponent {
|
|||||||
menuCategoriesResource = this.menuCategoryService.list();
|
menuCategoriesResource = this.menuCategoryService.list();
|
||||||
listResource = this.temporalProductService.list();
|
listResource = this.temporalProductService.list();
|
||||||
|
|
||||||
menuCategoryFilter = signal<string>('');
|
|
||||||
saleCategoryFilter = signal<string>('');
|
|
||||||
|
|
||||||
formModel = signal<TemporalProductListFormData>({
|
formModel = signal<TemporalProductListFormData>({
|
||||||
filter: '',
|
filter: '',
|
||||||
menuCategory: '',
|
menuCategory: '',
|
||||||
@@ -56,6 +52,9 @@ export class TemporalProductListComponent {
|
|||||||
|
|
||||||
form = form(this.formModel);
|
form = form(this.formModel);
|
||||||
|
|
||||||
|
menuCategoryFilter = computed(() => this.formModel().menuCategory ?? '');
|
||||||
|
saleCategoryFilter = computed(() => this.formModel().saleCategory ?? '');
|
||||||
|
|
||||||
filterSignal = computed(() => this.formModel().filter);
|
filterSignal = computed(() => this.formModel().filter);
|
||||||
debouncedFilter = debounced(this.filterSignal, 150);
|
debouncedFilter = debounced(this.filterSignal, 150);
|
||||||
|
|
||||||
@@ -79,12 +78,4 @@ export class TemporalProductListComponent {
|
|||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns: string[] = ['product', 'sku', 'price', 'menuCategory', 'saleCategory', 'info'];
|
displayedColumns: string[] = ['product', 'sku', 'price', 'menuCategory', 'saleCategory', 'info'];
|
||||||
|
|
||||||
filterMcOn(val: string) {
|
|
||||||
this.menuCategoryFilter.set(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
filterScOn(val: string) {
|
|
||||||
this.saleCategoryFilter.set(val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ 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 { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { MenuCategoryService } from '../menu-category/menu-category.service';
|
import { MenuCategoryService } from '../menu-category/menu-category.service';
|
||||||
@@ -43,7 +43,6 @@ export interface UpdateProductPricesFormData {
|
|||||||
})
|
})
|
||||||
export class UpdateProductPricesComponent {
|
export class UpdateProductPricesComponent {
|
||||||
private menuCategoryService = inject(MenuCategoryService);
|
private menuCategoryService = inject(MenuCategoryService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private toCsv = inject(ToCsvService);
|
private toCsv = inject(ToCsvService);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { User } from '../../core/user';
|
import { User } from '../../core/user';
|
||||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||||
@@ -36,7 +36,6 @@ export interface UserDetailFormData {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class UserDetailComponent {
|
export class UserDetailComponent {
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
private router = inject(Router);
|
private router = inject(Router);
|
||||||
private snackBar = inject(MatSnackBar);
|
private snackBar = inject(MatSnackBar);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, computed, inject } from '@angular/core';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
import { LocalTimePipe } from '../../shared/local-time.pipe';
|
import { LocalTimePipe } from '../../shared/local-time.pipe';
|
||||||
import { UserService } from '../user.service';
|
import { UserService } from '../user.service';
|
||||||
@@ -14,7 +14,6 @@ import { UserService } from '../user.service';
|
|||||||
})
|
})
|
||||||
export class UserListComponent {
|
export class UserListComponent {
|
||||||
private userService = inject(UserService);
|
private userService = inject(UserService);
|
||||||
private route = inject(ActivatedRoute);
|
|
||||||
listResource = this.userService.list();
|
listResource = this.userService.list();
|
||||||
|
|
||||||
dataSource = computed(() => this.listResource.value() ?? []);
|
dataSource = computed(() => this.listResource.value() ?? []);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ npx ng lint --fix
|
|||||||
|
|
||||||
cd "$parent_path/barker" || exit
|
cd "$parent_path/barker" || exit
|
||||||
uv run ruff format .
|
uv run ruff format .
|
||||||
uv run ruff check .
|
uv run ruff check . --fix
|
||||||
uv run bandit --recursive barker
|
uv run bandit --recursive barker
|
||||||
uv run bandit --recursive .
|
uv run bandit --recursive .
|
||||||
uv run safety check
|
uv run safety check
|
||||||
@@ -31,6 +31,7 @@ then
|
|||||||
sed --in-place --regexp-extended 's/"([0-9]{1,2}.[0-9]+.[0-9]+)"/"'"$new_version"'"/g' barker/barker/__version__.py
|
sed --in-place --regexp-extended 's/"([0-9]{1,2}.[0-9]+.[0-9]+)"/"'"$new_version"'"/g' barker/barker/__version__.py
|
||||||
git add barker/barker/__version__.py
|
git add barker/barker/__version__.py
|
||||||
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' barker/pyproject.toml
|
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' barker/pyproject.toml
|
||||||
|
(cd barker && uv lock)
|
||||||
git add barker/pyproject.toml
|
git add barker/pyproject.toml
|
||||||
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' frank/pyproject.toml
|
sed --in-place --regexp-extended 's/version = "([0-9]{1,2}.[0-9]+.[0-9]+)"/version = "'"$new_version"'"/g' frank/pyproject.toml
|
||||||
git add frank/pyproject.toml
|
git add frank/pyproject.toml
|
||||||
@@ -45,4 +46,5 @@ else
|
|||||||
echo "Usage: $0 <major|minor|patch|version_string>"
|
echo "Usage: $0 <major|minor|patch|version_string>"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
git push
|
||||||
git push --tags
|
git push --tags
|
||||||
Reference in new issue
Block a user