Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
217f636573 | ||
|
|
95ac73bbc4 | ||
|
|
3d86f8706f | ||
|
|
30cbb60efe | ||
|
|
227f5b5f74 | ||
|
|
50974c7574 | ||
|
|
c8e1ab74b6 | ||
|
|
85ba7b326a |
Vendored
+2
-2
@@ -29,9 +29,9 @@
|
||||
"args": [
|
||||
"barker.main:app",
|
||||
"--host",
|
||||
"127.0.0.1",
|
||||
"0.0.0.0",
|
||||
"--port",
|
||||
"8000",
|
||||
"9995",
|
||||
"--reload"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/barker",
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "15.1.0"
|
||||
__version__ = "15.1.4"
|
||||
|
||||
@@ -121,7 +121,7 @@ def show_list(
|
||||
guest_book: list[schemas.GuestBookListItem] = []
|
||||
count = 0
|
||||
for i, item in enumerate(db.execute(list_).scalars().all()):
|
||||
status = GuestBookType(item.type_.name) if item.status is None else GuestBookType(item.status.status.name)
|
||||
item_status = GuestBookType(item.type_.name) if item.status is None else GuestBookType(item.status.status.name)
|
||||
if item.type_ != GuestBookType.booking:
|
||||
count += item.pax
|
||||
gbli = schemas.GuestBookListItem(
|
||||
@@ -134,7 +134,7 @@ def show_list(
|
||||
booking_date=item.booking_date,
|
||||
arrival_date=item.arrival_date,
|
||||
last_edit_date=item.last_edit_date,
|
||||
status=status,
|
||||
status=item_status,
|
||||
table_id=None if item.status is None else item.status.food_table.id,
|
||||
voucher_id=None if item.status is None else item.status.voucher_id,
|
||||
table_name=None if item.status is None else item.status.food_table.name,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "barker"
|
||||
version = "15.1.0"
|
||||
version = "15.1.4"
|
||||
description = "Point of Sale for a restaurant"
|
||||
requires-python = ">=3.14"
|
||||
authors = [{ name = "tanshu", email = "git@tanshu.com" }]
|
||||
|
||||
Generated
+1
-1
@@ -231,7 +231,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "barker"
|
||||
version = "15.1.0"
|
||||
version = "15.1.4"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
|
||||
+12
-5
@@ -32,7 +32,9 @@
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": ["src/styles.sass"],
|
||||
"styles": [
|
||||
"src/styles.sass"
|
||||
],
|
||||
"allowedCommonJsDependencies": [
|
||||
"typed-function",
|
||||
"javascript-natural-sort",
|
||||
@@ -46,8 +48,8 @@
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
"maximumWarning": "1000kb",
|
||||
"maximumError": "2mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
@@ -86,14 +88,19 @@
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"schematicCollections": ["@angular-eslint/schematics"],
|
||||
"schematicCollections": [
|
||||
"@angular-eslint/schematics"
|
||||
],
|
||||
"analytics": false
|
||||
},
|
||||
"schematics": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bookie",
|
||||
"version": "15.1.0",
|
||||
"version": "15.1.4",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
|
||||
version: '15.1.0',
|
||||
version: '15.1.4',
|
||||
};
|
||||
|
||||
export const dateFormat = {
|
||||
|
||||
@@ -42,13 +42,13 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select [formField]="form.saleCategory">
|
||||
@for (sc of saleCategories(); track sc) {
|
||||
@for (sc of saleCategories(); track sc.id) {
|
||||
<mat-option [value]="sc.id">
|
||||
{{ sc.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@for (error of form.saleCategory().errors(); track error) {
|
||||
@for (error of form.saleCategory().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@@ -1,39 +1,33 @@
|
||||
@if (productsResource.isLoading()) {
|
||||
<app-skeleton-loader type="card" [count]="1" />
|
||||
} @else if (productsResource.error()) {
|
||||
<app-error-state (retryAction)="productsResource.reload()" />
|
||||
} @else {
|
||||
<h1 mat-dialog-title>Edit Bundle Item</h1>
|
||||
<h1 mat-dialog-title>Edit Bundle Item</h1>
|
||||
|
||||
<div mat-dialog-content>
|
||||
<form>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Item</mat-label>
|
||||
<input matInput type="text" [formField]="form.product" [matAutocomplete]="autoP" />
|
||||
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn">
|
||||
@for (p of products(); track p) {
|
||||
<mat-option [value]="p">{{ p.name }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
<div mat-dialog-content>
|
||||
<form>
|
||||
<mat-form-field class="w-full">
|
||||
<mat-label>Item</mat-label>
|
||||
<input matInput type="text" [formField]="form.product" [matAutocomplete]="autoP" />
|
||||
<mat-autocomplete #autoP="matAutocomplete" [displayWith]="displayFn">
|
||||
@for (p of products(); track p.id) {
|
||||
<mat-option [value]="p">{{ p.name }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-3">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input matInput type="number" [formField]="form.quantity" />
|
||||
</mat-form-field>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-3">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input matInput type="number" [formField]="form.quantity" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.salePrice" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox [formField]="form.printInBill" class="flex-auto">Print in Bill?</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.salePrice" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox [formField]="form.printInBill" class="flex-auto">Print in Bill?</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-raised-button color="warn" [mat-dialog-close]="false">Cancel</button>
|
||||
<button type="button" mat-raised-button color="primary" (click)="accept()">Ok</button>
|
||||
</div>
|
||||
}
|
||||
<div mat-dialog-actions>
|
||||
<button mat-raised-button color="warn" [mat-dialog-close]="false">Cancel</button>
|
||||
<button type="button" mat-raised-button color="primary" (click)="accept()">Ok</button>
|
||||
</div>
|
||||
|
||||
@@ -10,8 +10,6 @@ import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { ProductQuery } from '../../core/product-query';
|
||||
import { ProductService } from '../../product/product.service';
|
||||
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||
import { BundleItem } from '../bundle';
|
||||
|
||||
export interface BundleDetailDialogFormData {
|
||||
@@ -35,8 +33,6 @@ export interface BundleDetailDialogFormData {
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
FormField,
|
||||
ErrorStateComponent,
|
||||
SkeletonLoaderComponent,
|
||||
],
|
||||
})
|
||||
export class BundleDetailDialogComponent {
|
||||
@@ -62,12 +58,15 @@ export class BundleDetailDialogComponent {
|
||||
return typeof p === 'string' ? p.trim() : '';
|
||||
});
|
||||
|
||||
debouncedProduct = debounced(this.productSignal, 150);
|
||||
debouncedProduct = debounced(this.productSignal, 300);
|
||||
|
||||
productsResource = this.productSer.query(this.debouncedProduct.value);
|
||||
products = computed(() => {
|
||||
if (!this.debouncedProduct.value()) return [];
|
||||
return this.productsResource.value() ?? [];
|
||||
products = linkedSignal<ProductQuery[] | undefined, ProductQuery[]>({
|
||||
source: () => this.productsResource.value(),
|
||||
computation: (newVal, previous) => {
|
||||
if (!this.debouncedProduct.value()) return [];
|
||||
return newVal ?? previous?.value ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
displayFn(product?: ProductQuery | string): string {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
@for (mc of menuCategories(); track mc) {
|
||||
@for (mc of menuCategories(); track mc.id) {
|
||||
<mat-option [value]="mc">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
@@ -39,7 +39,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select [formField]="form.saleCategory">
|
||||
@for (sc of saleCategories(); track sc) {
|
||||
@for (sc of saleCategories(); track sc.id) {
|
||||
<mat-option [value]="sc">
|
||||
{{ sc.name }}
|
||||
</mat-option>
|
||||
@@ -71,7 +71,7 @@
|
||||
[value]="displayFn(formModel().addRow.sku)"
|
||||
/>
|
||||
<mat-autocomplete #autoItem="matAutocomplete" [displayWith]="displayFn">
|
||||
@for (p of itemProducts(); track p) {
|
||||
@for (p of itemProducts(); track p.id) {
|
||||
<mat-option [value]="p">{{ p.name }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
|
||||
@@ -109,11 +109,15 @@ export class BundleDetailComponent {
|
||||
return typeof v === 'string' ? v : null;
|
||||
});
|
||||
|
||||
debouncedItemProduct = debounced(this.itemProductSearch, 150);
|
||||
debouncedItemProduct = debounced(this.itemProductSearch, 300);
|
||||
|
||||
itemProductsResource = this.productSer.query(this.debouncedItemProduct.value);
|
||||
itemProducts = computed(() => {
|
||||
return this.itemProductsResource.value() ?? [];
|
||||
itemProducts = linkedSignal<ProductQuery[] | undefined, ProductQuery[]>({
|
||||
source: () => this.itemProductsResource.value(),
|
||||
computation: (newVal, previous) => {
|
||||
if (!this.debouncedItemProduct.value()) return [];
|
||||
return newVal ?? previous?.value ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
displayedColumns = ['name', 'quantity', 'salePrice', 'printInBill', 'action'];
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
<mat-option [value]="null">-- All Bundles --</mat-option>
|
||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||
@for (mc of menuCategoriesResource.value(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
@@ -73,7 +73,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Items</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<div class="items-list">
|
||||
@for (item of row.items; track item) {
|
||||
@for (item of row.items; track item.id) {
|
||||
<mat-icon>
|
||||
{{ item.printInBill ? 'visibility' : 'visibility_off' }}
|
||||
</mat-icon>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<mat-label>Cashier</mat-label>
|
||||
<mat-select [formField]="form.cashier">
|
||||
<mat-option [value]="null">-- Cashier --</mat-option>
|
||||
@for (ac of cashiers(); track ac) {
|
||||
@for (ac of cashiers(); track ac.id) {
|
||||
<mat-option [value]="ac.id">
|
||||
{{ ac.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -10,6 +10,11 @@ import { AuthService } from '../auth/auth.service';
|
||||
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
|
||||
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
const authService = inject(AuthService);
|
||||
const snackBar = inject(MatSnackBar);
|
||||
const dialog = inject(MatDialog);
|
||||
const router = inject(Router);
|
||||
|
||||
return next(req).pipe(
|
||||
catchError((err) => {
|
||||
// We don't want to refresh token for some requests like login or refresh token itself
|
||||
@@ -18,34 +23,36 @@ export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
// We do another check to see if refresh token failed
|
||||
// In this case we want to logout user and to redirect it to login page
|
||||
if (req.url.includes('/refresh')) {
|
||||
inject(AuthService).logout();
|
||||
authService.logout();
|
||||
}
|
||||
return throwError(() => err);
|
||||
}
|
||||
// If error status is different than 401 we want to skip refresh token
|
||||
// So we check that and throw the error if it's the case
|
||||
if (err.status !== 401) {
|
||||
const error = err.error.message || err.error.detail || err.statusText;
|
||||
const error = err.error?.message || err.error?.detail || err.statusText || err;
|
||||
return throwError(() => error);
|
||||
}
|
||||
// auto logout if 401 response returned from api
|
||||
inject(AuthService).logout();
|
||||
inject(MatSnackBar).open('User has been logged out', 'Danger');
|
||||
const dialogRef = inject(MatDialog).open(ConfirmDialogComponent, {
|
||||
width: '250px',
|
||||
data: {
|
||||
title: 'Logged out!',
|
||||
content:
|
||||
'You have been logged out.\n' +
|
||||
'You can press Cancel to stay on page and login in another tab to resume here, ' +
|
||||
'or you can press Ok to navigate to the login page.',
|
||||
},
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((result: boolean) => {
|
||||
if (result) {
|
||||
inject(Router).navigate(['login']);
|
||||
}
|
||||
});
|
||||
authService.logout();
|
||||
if (dialog.openDialogs.length === 0) {
|
||||
snackBar.open('User has been logged out', 'Danger');
|
||||
const dialogRef = dialog.open(ConfirmDialogComponent, {
|
||||
width: '350px',
|
||||
data: {
|
||||
title: 'Logged out!',
|
||||
content:
|
||||
'You have been logged out.\n' +
|
||||
'You can press Cancel to stay on page and login in another tab to resume here, ' +
|
||||
'or you can press Ok to navigate to the login page.',
|
||||
},
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((result: boolean) => {
|
||||
if (result) {
|
||||
router.navigate(['/login']);
|
||||
}
|
||||
});
|
||||
}
|
||||
return throwError(() => err);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="discounts">
|
||||
@for (r of item().discounts; track r; let i = $index) {
|
||||
@for (r of item().discounts; track r.id; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Discount on {{ r.name }}</mat-label>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Discounts</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (discount of row.discounts; track discount) {
|
||||
@for (discount of row.discounts; track discount.id) {
|
||||
<li>{{ discount.name }} - {{ discount.discount | percent: '1.2-2' }}</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Section</mat-label>
|
||||
<mat-select [formField]="form.section">
|
||||
@for (s of sections(); track s) {
|
||||
@for (s of sections(); track s.id) {
|
||||
<mat-option [value]="s.id">
|
||||
{{ s.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
[displayWith]="displayFn"
|
||||
(optionSelected)="selected($event)"
|
||||
>
|
||||
@for (customer of customers(); track customer) {
|
||||
@for (customer of customers(); track customer.id) {
|
||||
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
|
||||
@@ -95,12 +95,15 @@ export class GuestBookDetailComponent {
|
||||
return typeof p === 'string' ? p.trim() : (p as Customer).phone;
|
||||
});
|
||||
|
||||
debouncedPhone = debounced(this.phoneSignal, 150);
|
||||
debouncedPhone = debounced(this.phoneSignal, 300);
|
||||
|
||||
customersResource = this.customerService.autocomplete(computed(() => this.debouncedPhone.value()));
|
||||
customers = computed(() => {
|
||||
if (!this.debouncedPhone.value()) return [];
|
||||
return this.customersResource.value() ?? [];
|
||||
customers = linkedSignal<Customer[] | undefined, Customer[]>({
|
||||
source: () => this.customersResource.value(),
|
||||
computation: (newVal, previous) => {
|
||||
if (!this.debouncedPhone.value()) return [];
|
||||
return newVal ?? previous?.value ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Header / Footer</mat-label>
|
||||
<mat-select [formField]="form.id" (selectionChange)="show($event)">
|
||||
@for (s of list(); track s) {
|
||||
@for (s of list(); track s.id) {
|
||||
<mat-option [value]="s.id">
|
||||
{{ s.name }}
|
||||
</mat-option>
|
||||
|
||||
+2
-2
@@ -47,12 +47,12 @@
|
||||
<mat-header-cell *matHeaderCellDef>Products</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (mc of row.menuCategories; track mc) {
|
||||
@for (mc of row.menuCategories; track mc.id) {
|
||||
<li>
|
||||
{{ mc.name }}
|
||||
@if (!mc.enabled) {
|
||||
<ul>
|
||||
@for (p of mc.skus; track p) {
|
||||
@for (p of mc.skus; track p.id) {
|
||||
<li>{{ p.name }}</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Category</mat-label>
|
||||
<mat-select [formField]="form.modifierCategory">
|
||||
@for (mc of modifierCategories(); track mc) {
|
||||
@for (mc of modifierCategories(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@for (error of form.modifierCategory().errors(); track error) {
|
||||
@for (error of form.modifierCategory().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput [formField]="form.units" />
|
||||
@for (error of form.units().errors(); track error) {
|
||||
@for (error of form.units().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -13,7 +13,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" [formField]="form.fraction" />
|
||||
@for (error of form.fraction().errors(); track error) {
|
||||
@for (error of form.fraction().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -21,7 +21,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" [formField]="form.productYield" />
|
||||
@for (error of form.productYield().errors(); track error) {
|
||||
@for (error of form.productYield().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -29,7 +29,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Cost Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.costPrice" />
|
||||
@for (error of form.costPrice().errors(); track error) {
|
||||
@for (error of form.costPrice().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -37,7 +37,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.salePrice" />
|
||||
@for (error of form.salePrice().errors(); track error) {
|
||||
@for (error of form.salePrice().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -45,7 +45,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
@for (mc of menuCategories; track mc) {
|
||||
@for (mc of menuCategories; track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<mat-form-field class="basis-3-4">
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select [formField]="form.saleCategory">
|
||||
@for (sc of saleCategories(); track sc) {
|
||||
@for (sc of saleCategories(); track sc.id) {
|
||||
<mat-option [value]="sc.id">
|
||||
{{ sc.name }}
|
||||
</mat-option>
|
||||
@@ -35,7 +35,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput [formField]="form.addRow.units" />
|
||||
@for (error of form.addRow.units().errors(); track error) {
|
||||
@for (error of form.addRow.units().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -43,7 +43,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" [formField]="form.addRow.fraction" />
|
||||
@for (error of form.addRow.fraction().errors(); track error) {
|
||||
@for (error of form.addRow.fraction().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -51,7 +51,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" [formField]="form.addRow.productYield" />
|
||||
@for (error of form.addRow.productYield().errors(); track error) {
|
||||
@for (error of form.addRow.productYield().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -59,7 +59,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Cost Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.addRow.costPrice" />
|
||||
@for (error of form.addRow.costPrice().errors(); track error) {
|
||||
@for (error of form.addRow.costPrice().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -67,7 +67,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" [formField]="form.addRow.salePrice" />
|
||||
@for (error of form.addRow.salePrice().errors(); track error) {
|
||||
@for (error of form.addRow.salePrice().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
@@ -75,13 +75,13 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.addRow.menuCategory">
|
||||
@for (mc of menuCategories(); track mc) {
|
||||
@for (mc of menuCategories(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
@for (error of form.addRow.menuCategory().errors(); track error) {
|
||||
@for (error of form.addRow.menuCategory().errors(); track $index) {
|
||||
<mat-error>{{ error.message }}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
<mat-option [value]="null">-- All Products --</mat-option>
|
||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||
@for (mc of menuCategoriesResource.value(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
@@ -54,7 +54,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (sku of row.skus; track sku) {
|
||||
@for (sku of row.skus; track sku.id) {
|
||||
<li>
|
||||
<a [routerLink]="['/products', row.id]">{{ row.name }} ({{ sku.units }})</a>
|
||||
</li>
|
||||
@@ -68,7 +68,7 @@
|
||||
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">
|
||||
<ul>
|
||||
@for (sku of row.skus; track sku) {
|
||||
@for (sku of row.skus; track sku.id) {
|
||||
<li>
|
||||
{{ sku.salePrice | currency: 'INR' }}
|
||||
</li>
|
||||
@@ -82,7 +82,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Menu Category</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (sku of row.skus; track sku) {
|
||||
@for (sku of row.skus; track sku.id) {
|
||||
<li>
|
||||
{{ sku.menuCategory.name }}
|
||||
</li>
|
||||
@@ -102,7 +102,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Details</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (sku of row.skus; track sku) {
|
||||
@for (sku of row.skus; track sku.id) {
|
||||
<li layout="row">
|
||||
<div>
|
||||
<mat-icon>
|
||||
@@ -127,7 +127,7 @@
|
||||
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">
|
||||
<ul>
|
||||
@for (sku of row.skus; track sku) {
|
||||
@for (sku of row.skus; track sku.id) {
|
||||
<li>{{ sku.fraction | number: '1.2-2' }}{{ row.fractionUnits }}</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="two-col">
|
||||
<div class="col">
|
||||
<h3>Permissions</h3>
|
||||
@for (p of form.permissions; track p; let i = $index) {
|
||||
@for (p of form.permissions; track p.id().value() || i; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox
|
||||
[formField]="p.enabled"
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<div class="col">
|
||||
<h3>Includes Roles</h3>
|
||||
@for (r of form.includedRoles; track r; let i = $index) {
|
||||
@for (r of form.includedRoles; track r.id().value() || i; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox [formField]="r.enabled" class="flex-auto">{{ r.name().value() }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Tax</mat-label>
|
||||
<mat-select [formField]="form.tax">
|
||||
@for (t of taxes(); track t) {
|
||||
@for (t of taxes(); track t.id) {
|
||||
<mat-option [value]="t.id">
|
||||
{{ t.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<mat-form-field class="flex-auto basis-15">
|
||||
<mat-label>Regime</mat-label>
|
||||
<mat-select [formField]="form.regime">
|
||||
@for (r of regimes; track r) {
|
||||
@for (r of regimes; track r.id) {
|
||||
<mat-option [value]="r">
|
||||
{{ r.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -37,25 +37,36 @@ export class BillService {
|
||||
|
||||
public grossAmount = computed(() =>
|
||||
this.math.halfRoundEven(
|
||||
this.data().reduce((t, k) => k.inventories.reduce((a, c) => a + c.price * c.quantity, 0) + t, 0),
|
||||
this.data().reduce(
|
||||
(t, k) => k.inventories.filter((c) => !c.parentId).reduce((a, c) => a + c.price * c.quantity, 0) + t,
|
||||
0,
|
||||
),
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
public hhAmount = computed(() =>
|
||||
this.math.halfRoundEven(
|
||||
this.data().reduce(
|
||||
(t, k) => k.inventories.reduce((a, c) => a + (c.isHappyHour ? c.price : 0) * c.quantity, 0) + t,
|
||||
(t, k) =>
|
||||
k.inventories.filter((c) => !c.parentId).reduce((a, c) => a + (c.isHappyHour ? c.price : 0) * c.quantity, 0) +
|
||||
t,
|
||||
0,
|
||||
),
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
public discountAmount = computed(() =>
|
||||
this.math.halfRoundEven(
|
||||
this.data().reduce(
|
||||
(t, k) => k.inventories.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount, 0) + t,
|
||||
(t, k) =>
|
||||
k.inventories
|
||||
.filter((c) => !c.parentId)
|
||||
.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount, 0) + t,
|
||||
0,
|
||||
),
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -63,16 +74,36 @@ export class BillService {
|
||||
this.math.halfRoundEven(
|
||||
this.data().reduce(
|
||||
(t, k) =>
|
||||
k.inventories.reduce(
|
||||
(a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate,
|
||||
0,
|
||||
) + t,
|
||||
k.inventories
|
||||
.filter((c) => !c.parentId)
|
||||
.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate, 0) + t,
|
||||
0,
|
||||
),
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
public amount = computed(() =>
|
||||
this.math.halfRoundEven(
|
||||
this.data().reduce(
|
||||
(t, k) =>
|
||||
k.inventories
|
||||
.filter((c) => !c.parentId)
|
||||
.reduce(
|
||||
(a, c) =>
|
||||
a +
|
||||
this.math.halfRoundEven(
|
||||
(c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
|
||||
2,
|
||||
),
|
||||
0,
|
||||
) + t,
|
||||
0,
|
||||
),
|
||||
0,
|
||||
),
|
||||
);
|
||||
|
||||
public amount = computed(() => this.grossAmount() - this.discountAmount() + this.taxAmount());
|
||||
public selection = new SelectionModel<string>(true, []);
|
||||
private updateTable = signal<boolean>(true);
|
||||
private allowDeactivate = signal<boolean>(false);
|
||||
|
||||
@@ -1,63 +1,57 @@
|
||||
@if (customersResource.isLoading()) {
|
||||
<app-skeleton-loader type="card" [count]="1" />
|
||||
} @else if (customersResource.error()) {
|
||||
<app-error-state (retryAction)="customersResource.reload()" />
|
||||
} @else {
|
||||
<h2 mat-dialog-title>Customer</h2>
|
||||
<mat-dialog-content>
|
||||
<form class="flex-col">
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[formField]="form.phone"
|
||||
[matAutocomplete]="auto"
|
||||
autocomplete="off"
|
||||
cdkFocusInitial
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-autocomplete
|
||||
#auto="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayFn"
|
||||
(optionSelected)="selected($event)"
|
||||
>
|
||||
@for (customer of customers(); track customer) {
|
||||
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
|
||||
<h2 mat-dialog-title>Customer</h2>
|
||||
<mat-dialog-content>
|
||||
<form class="flex-col">
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
[formField]="form.phone"
|
||||
[matAutocomplete]="auto"
|
||||
autocomplete="off"
|
||||
cdkFocusInitial
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-autocomplete
|
||||
#auto="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayFn"
|
||||
(optionSelected)="selected($event)"
|
||||
>
|
||||
@for (customer of customers(); track customer.id) {
|
||||
<mat-option [value]="customer">{{ customer.name }} - {{ customer.phone }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput [value]="formModel().name" readonly />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Address</mat-label>
|
||||
<textarea matInput [value]="formModel().address" readonly> </textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-checkbox [checked]="formModel().printInBill" [disabled]="true">Print in Bill?</mat-checkbox>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="discounts">
|
||||
<ul>
|
||||
@for (r of formModel().discounts; track r.id) {
|
||||
@if (r.discount > 0) {
|
||||
<li>{{ r.name }} - {{ r.discount | percent: '1.2-2' }}</li>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput [value]="formModel().name" readonly />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Address</mat-label>
|
||||
<textarea matInput [value]="formModel().address" readonly> </textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-checkbox [checked]="formModel().printInBill" [disabled]="true">Print in Bill?</mat-checkbox>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="discounts">
|
||||
<ul>
|
||||
@for (r of formModel().discounts; track r.id) {
|
||||
@if (r.discount > 0) {
|
||||
<li>{{ r.name }} - {{ r.discount | percent: '1.2-2' }}</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button [mat-dialog-close]="false">Cancel</button>
|
||||
<button type="button" mat-raised-button color="primary" (click)="save()">Select</button>
|
||||
</mat-dialog-actions>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button [mat-dialog-close]="false">Cancel</button>
|
||||
<button type="button" mat-raised-button color="primary" (click)="save()">Select</button>
|
||||
</mat-dialog-actions>
|
||||
|
||||
@@ -13,8 +13,6 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { Customer } from '../../core/customer';
|
||||
import { CustomerDiscount } from '../../core/customer-discount';
|
||||
import { CustomerService } from '../../customers/customer.service';
|
||||
import { ErrorStateComponent } from '../../shared/error-state/error-state.component';
|
||||
import { SkeletonLoaderComponent } from '../../shared/skeleton-loader/skeleton-loader.component';
|
||||
|
||||
export interface ChooseCustomerFormData {
|
||||
id: string;
|
||||
@@ -40,8 +38,6 @@ export interface ChooseCustomerFormData {
|
||||
MatOptionModule,
|
||||
PercentPipe,
|
||||
FormField,
|
||||
ErrorStateComponent,
|
||||
SkeletonLoaderComponent,
|
||||
],
|
||||
})
|
||||
export class ChooseCustomerComponent {
|
||||
@@ -66,14 +62,19 @@ export class ChooseCustomerComponent {
|
||||
form = form(this.formModel);
|
||||
|
||||
phoneSignal = computed(() => {
|
||||
return this.formModel().phone;
|
||||
const p = this.formModel().phone;
|
||||
return typeof p === 'string' ? p.trim() : null;
|
||||
});
|
||||
|
||||
debouncedPhone = debounced(this.phoneSignal, 150);
|
||||
debouncedPhone = debounced(this.phoneSignal, 300);
|
||||
|
||||
customersResource = this.ser.autocomplete(this.debouncedPhone.value);
|
||||
customers = computed(() => {
|
||||
return this.customersResource.value() ?? [];
|
||||
customers = linkedSignal<Customer[] | undefined, Customer[]>({
|
||||
source: () => this.customersResource.value(),
|
||||
computation: (newVal, previous) => {
|
||||
if (!this.debouncedPhone.value()) return [];
|
||||
return newVal ?? previous?.value ?? [];
|
||||
},
|
||||
});
|
||||
|
||||
save() {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<mat-card class="flex-col square-button warn" matRipple [routerLink]="['../']" queryParamsHandling="preserve">
|
||||
<h3>Back</h3>
|
||||
</mat-card>
|
||||
@for (item of list(); track item) {
|
||||
@for (item of list(); track item.id) {
|
||||
<mat-card
|
||||
class="primary flex-col square-button"
|
||||
matRipple
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
>
|
||||
<h3>Back</h3>
|
||||
</mat-card>
|
||||
@for (item of list(); track item) {
|
||||
@for (item of list(); track item.id) {
|
||||
<mat-card
|
||||
class="flex-col square-button"
|
||||
matRipple
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h2>Running Tables</h2>
|
||||
|
||||
<div class="tables-grid">
|
||||
@for (table of list(); track table) {
|
||||
@for (table of list(); track table.id) {
|
||||
<mat-card
|
||||
class="flex-col square-button"
|
||||
matRipple
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<mat-dialog-content>
|
||||
<form class="flex-col">
|
||||
<div>
|
||||
@for (sc of list(); track sc; let i = $index) {
|
||||
@for (sc of list(); track sc.id; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox [formField]="form.saleCategories[i].saleCategory" class="flex-auto">{{ sc.name }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<h2 mat-dialog-title>Tables</h2>
|
||||
<mat-dialog-content>
|
||||
<div class="tables-grid">
|
||||
@for (table of list.value(); track table) {
|
||||
@for (table of list.value(); track table.id) {
|
||||
<mat-card
|
||||
class="flex-col square-button"
|
||||
matRipple
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Section</mat-label>
|
||||
<mat-select [formField]="form.section" (selectionChange)="show($event)">
|
||||
@for (s of sections(); track s) {
|
||||
@for (s of sections(); track s.id) {
|
||||
<mat-option [value]="s.id">
|
||||
{{ s.name }}
|
||||
</mat-option>
|
||||
@@ -33,7 +33,7 @@
|
||||
<mat-label>Printer</mat-label>
|
||||
<mat-select [formField]="form.saleCategories[i].printer">
|
||||
<mat-option [value]="null">-- Default --</mat-option>
|
||||
@for (p of printers(); track p) {
|
||||
@for (p of printers(); track p.id) {
|
||||
<mat-option [value]="p.id">
|
||||
{{ p.name }}
|
||||
</mat-option>
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Voucher Type</mat-label>
|
||||
<mat-select [formField]="form.voucherType">
|
||||
@for (vt of voucherTypes; track vt) {
|
||||
@for (vt of voucherTypes; track vt.id) {
|
||||
<mat-option [value]="vt.id">
|
||||
{{ vt.name }}
|
||||
</mat-option>
|
||||
@@ -25,7 +25,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Reporting Level</mat-label>
|
||||
<mat-select [formField]="form.reportingLevel">
|
||||
@for (rl of reportingLevel; track rl) {
|
||||
@for (rl of reportingLevel; track rl.id) {
|
||||
<mat-option [value]="rl.id">
|
||||
{{ rl.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Section</mat-label>
|
||||
<mat-select [formField]="form.section">
|
||||
@for (s of sections(); track s) {
|
||||
@for (s of sections(); track s.id) {
|
||||
<mat-option [value]="s.id">
|
||||
{{ s.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Regime</mat-label>
|
||||
<mat-select [formField]="form.regime">
|
||||
@for (reg of regimes(); track reg) {
|
||||
@for (reg of regimes(); track reg.id) {
|
||||
<mat-option [value]="reg.id">
|
||||
{{ reg.name }}
|
||||
</mat-option>
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select [formField]="productForm.saleCategory">
|
||||
@for (sc of saleCategories(); track sc) {
|
||||
@for (sc of saleCategories(); track sc.id) {
|
||||
<mat-option [value]="sc.id">
|
||||
{{ sc.name }}
|
||||
</mat-option>
|
||||
@@ -131,7 +131,7 @@
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="skuForm.menuCategory">
|
||||
@for (mc of menuCategories(); track mc) {
|
||||
@for (mc of menuCategories(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
<mat-option [value]="null">-- All Products --</mat-option>
|
||||
@for (mc of menuCategoriesResource.value(); track mc) {
|
||||
@for (mc of menuCategoriesResource.value(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
@@ -25,7 +25,7 @@
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select [formField]="form.saleCategory">
|
||||
<mat-option [value]="null">-- All Products --</mat-option>
|
||||
@for (mc of saleCategoriesResource.value(); track mc) {
|
||||
@for (mc of saleCategoriesResource.value(); track mc.id) {
|
||||
<mat-option [value]="mc.id">
|
||||
{{ mc.name }}
|
||||
</mat-option>
|
||||
@@ -40,7 +40,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Products</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (p of row.products; track p) {
|
||||
@for (p of row.products; track p.versionId) {
|
||||
<li>
|
||||
<a [routerLink]="['/temporal-products', p.id]">
|
||||
<b>{{ p.name }}</b>
|
||||
@@ -61,7 +61,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>Skus</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
@for (s of row.skus; track s) {
|
||||
@for (s of row.skus; track s.versionId) {
|
||||
<li>
|
||||
{{ s.units }}
|
||||
</li>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<mat-form-field class="flex-auto basis-2-5">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select [formField]="form.menuCategory">
|
||||
@for (s of menuCategories(); track s) {
|
||||
@for (s of menuCategories(); track s.id) {
|
||||
<mat-option [value]="s.id">
|
||||
{{ s.name }}
|
||||
</mat-option>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div>
|
||||
@for (r of form.roles; track r; let i = $index) {
|
||||
@for (r of form.roles; track r.id().value() || i; let i = $index) {
|
||||
<div class="row-container">
|
||||
<mat-checkbox [formField]="r.enabled" class="flex-auto">{{ r.name().value() }}</mat-checkbox>
|
||||
</div>
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
when: var_file is defined
|
||||
|
||||
roles:
|
||||
- printer
|
||||
- frank
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
- name: Reload udev
|
||||
ansible.builtin.shell: udevadm control --reload-rules && udevadm trigger --action=change
|
||||
@@ -0,0 +1,7 @@
|
||||
- name: Add udev rule for usb printer systemd tag
|
||||
copy:
|
||||
dest: /etc/udev/rules.d/99-usb-printers.rules
|
||||
content: |
|
||||
SUBSYSTEM=="usbmisc", KERNEL=="lp*", TAG+="systemd"
|
||||
mode: "0644"
|
||||
notify: Reload udev
|
||||
Reference in New Issue
Block a user