Bundle item has an option to not print in the bill.
Bills and Kots should print properly with bundles
This commit is contained in:
@ -22,6 +22,7 @@
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox formControlName="printInBill" class="flex-auto">Print in Bill?</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
@ -18,9 +19,10 @@ import { BundleItem } from '../bundle';
|
||||
styleUrls: ['./bundle-detail-dialog.component.css'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
CommonModule,
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
MatDialogModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
@ -40,6 +42,7 @@ export class BundleDetailDialogComponent implements OnInit {
|
||||
product: FormControl<ProductQuery | string>;
|
||||
quantity: FormControl<number>;
|
||||
salePrice: FormControl<number>;
|
||||
printInBill: FormControl<boolean>;
|
||||
}>;
|
||||
|
||||
constructor() {
|
||||
@ -47,6 +50,7 @@ export class BundleDetailDialogComponent implements OnInit {
|
||||
product: new FormControl<ProductQuery | string>('', { nonNullable: true }),
|
||||
quantity: new FormControl<number>(1, { nonNullable: true }),
|
||||
salePrice: new FormControl<number>(0, { nonNullable: true }),
|
||||
printInBill: new FormControl<boolean>(true, { nonNullable: true }),
|
||||
});
|
||||
|
||||
this.products$ = this.form.controls.product.valueChanges.pipe(
|
||||
@ -70,6 +74,7 @@ export class BundleDetailDialogComponent implements OnInit {
|
||||
product: this.data.item.name ?? '',
|
||||
quantity: Number(this.data.item.quantity ?? 1),
|
||||
salePrice: Number(this.data.item.salePrice ?? 0),
|
||||
printInBill: this.data.item.printInBill,
|
||||
});
|
||||
|
||||
this.selectedProduct = null;
|
||||
@ -104,6 +109,7 @@ export class BundleDetailDialogComponent implements OnInit {
|
||||
|
||||
this.data.item.quantity = quantity;
|
||||
this.data.item.salePrice = salePrice;
|
||||
this.data.item.printInBill = v.printInBill || false;
|
||||
|
||||
this.dialogRef.close(this.data.item);
|
||||
}
|
||||
|
||||
@ -14,13 +14,13 @@
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<mat-form-field class="basis-1-4">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" formControlName="salePrice" readonly="" />
|
||||
<mat-hint>Computed from bundle items</mat-hint>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="basis-2-4">
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Menu Category</mat-label>
|
||||
<mat-select formControlName="menuCategory">
|
||||
@for (mc of menuCategories; track mc) {
|
||||
@ -31,8 +31,26 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox formControlName="hasHappyHour" class="basis-1-4">Has Happy Hour?</mat-checkbox>
|
||||
<mat-checkbox formControlName="isNotAvailable" class="basis-1-4">Not Available?</mat-checkbox>
|
||||
<mat-form-field class="flex-auto">
|
||||
<mat-label>Sale Category</mat-label>
|
||||
<mat-select formControlName="saleCategory">
|
||||
@for (sc of saleCategories; track sc) {
|
||||
<mat-option [value]="sc.id">
|
||||
{{ sc.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<span class="flex-auto"
|
||||
>Sale Category is used for Tax Report and displaying in the right bill regimes. For the Sale Report, Discount
|
||||
Report and Beer Sale Report, the Sale Category from the Bundle Items is used.</span
|
||||
>
|
||||
</div>
|
||||
<div class="row-container">
|
||||
<mat-checkbox formControlName="hasHappyHour" class="flex-auto">Has Happy Hour?</mat-checkbox>
|
||||
<mat-checkbox formControlName="isNotAvailable" class="flex-auto">Not Available?</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<h2>Items</h2>
|
||||
@ -63,6 +81,7 @@
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
<mat-checkbox formControlName="printInBill" class="basis-1-4">Print in Bill?</mat-checkbox>
|
||||
|
||||
<button mat-raised-button color="primary" (click)="addRow()" class="flex-auto">Add</button>
|
||||
</div>
|
||||
@ -94,6 +113,16 @@
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Sale Price Column -->
|
||||
<ng-container matColumnDef="printInBill">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Print in Bill</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">
|
||||
<mat-icon>
|
||||
{{ row.printInBill ? 'visibility' : 'visibility_off' }}
|
||||
</mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Action Column -->
|
||||
<ng-container matColumnDef="action">
|
||||
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
|
||||
|
||||
@ -17,6 +17,7 @@ import { of as observableOf, BehaviorSubject, debounceTime, distinctUntilChanged
|
||||
|
||||
import { MenuCategory } from '../../core/menu-category';
|
||||
import { ProductQuery } from '../../core/product-query';
|
||||
import { SaleCategory } from '../../core/sale-category';
|
||||
import { ProductService } from '../../product/product.service';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { Bundle, BundleItem } from '../bundle';
|
||||
@ -59,6 +60,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
units: FormControl<string>;
|
||||
salePrice: FormControl<number>;
|
||||
menuCategory: FormControl<string>;
|
||||
saleCategory: FormControl<string>;
|
||||
hasHappyHour: FormControl<boolean>;
|
||||
isNotAvailable: FormControl<boolean>;
|
||||
|
||||
@ -67,10 +69,12 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
itemId: FormControl<ProductQuery | string>;
|
||||
quantity: FormControl<number>;
|
||||
salePrice: FormControl<number>;
|
||||
printInBill: FormControl<boolean>;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
menuCategories: MenuCategory[] = [];
|
||||
saleCategories: SaleCategory[] = [];
|
||||
public items$ = new BehaviorSubject<BundleItem[]>([]);
|
||||
dataSource: BundleDetailDatasource = new BundleDetailDatasource(this.items$);
|
||||
|
||||
@ -79,7 +83,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
itemProduct: ProductQuery | null = null;
|
||||
itemProducts: Observable<ProductQuery[]>;
|
||||
|
||||
displayedColumns = ['name', 'quantity', 'salePrice', 'action'];
|
||||
displayedColumns = ['name', 'quantity', 'salePrice', 'printInBill', 'action'];
|
||||
|
||||
constructor() {
|
||||
this.form = new FormGroup({
|
||||
@ -87,6 +91,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
units: new FormControl<string>('', { nonNullable: true }),
|
||||
salePrice: new FormControl<number>(0, { nonNullable: true }),
|
||||
menuCategory: new FormControl<string>('', { nonNullable: true }),
|
||||
saleCategory: new FormControl<string>('', { nonNullable: true }),
|
||||
hasHappyHour: new FormControl<boolean>(false, { nonNullable: true }),
|
||||
isNotAvailable: new FormControl<boolean>(false, { nonNullable: true }),
|
||||
|
||||
@ -94,6 +99,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
itemId: new FormControl<ProductQuery | string>('', { nonNullable: true }),
|
||||
quantity: new FormControl<number>(1, { nonNullable: true }),
|
||||
salePrice: new FormControl<number>(0, { nonNullable: true }),
|
||||
printInBill: new FormControl<boolean>(true, { nonNullable: true }),
|
||||
}),
|
||||
});
|
||||
this.itemProducts = this.form.controls.addRow.controls.itemId.valueChanges.pipe(
|
||||
@ -119,8 +125,10 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
const data = value as {
|
||||
item: Bundle;
|
||||
menuCategories: MenuCategory[];
|
||||
saleCategories: SaleCategory[];
|
||||
};
|
||||
this.menuCategories = data.menuCategories;
|
||||
this.saleCategories = data.saleCategories;
|
||||
this.showItem(data.item);
|
||||
});
|
||||
}
|
||||
@ -158,6 +166,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
units: this.item.units ?? '',
|
||||
salePrice: Number(this.item.salePrice ?? 0),
|
||||
menuCategory: this.item.menuCategory?.id ?? '',
|
||||
saleCategory: this.item.saleCategory?.id ?? '',
|
||||
hasHappyHour: this.item.hasHappyHour ?? false,
|
||||
isNotAvailable: this.item.isNotAvailable ?? false,
|
||||
|
||||
@ -165,6 +174,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
itemId: '',
|
||||
quantity: 1,
|
||||
salePrice: 0,
|
||||
printInBill: true,
|
||||
},
|
||||
});
|
||||
this.itemProduct = null;
|
||||
@ -217,6 +227,7 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
name: this.itemProduct?.name ?? '',
|
||||
quantity,
|
||||
salePrice,
|
||||
printInBill: v.printInBill || false,
|
||||
});
|
||||
|
||||
this.item.items.push(bi);
|
||||
@ -315,6 +326,19 @@ export class BundleDetailComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
this.item.menuCategory.id = menuCategoryId;
|
||||
|
||||
// sale category
|
||||
const saleCategoryId = v.saleCategory ?? '';
|
||||
if (!saleCategoryId) {
|
||||
// keep it as-is; backend will 422 anyway, but we can show UI error too
|
||||
this.snackBar.open('Menu Category is required', 'Error');
|
||||
return this.item;
|
||||
}
|
||||
|
||||
if (this.item.saleCategory === null || this.item.saleCategory === undefined) {
|
||||
this.item.saleCategory = new SaleCategory();
|
||||
}
|
||||
this.item.saleCategory.id = saleCategoryId;
|
||||
|
||||
// ensure items array exists
|
||||
if (!this.item.items) {
|
||||
this.item.items = [];
|
||||
|
||||
@ -55,12 +55,23 @@
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Sale Category -->
|
||||
<ng-container matColumnDef="saleCategory">
|
||||
<mat-header-cell *matHeaderCellDef>Sale Category</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
{{ row.saleCategory?.name }}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Items -->
|
||||
<ng-container matColumnDef="items">
|
||||
<mat-header-cell *matHeaderCellDef>Items</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<div class="items-list">
|
||||
@for (item of row.items; track item) {
|
||||
<mat-icon>
|
||||
{{ item.printInBill ? 'visibility' : 'visibility_off' }}
|
||||
</mat-icon>
|
||||
<div class="item-name">{{ item.name }} x {{ item.quantity }} @ {{ item.salePrice | currency: 'INR' }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -51,7 +51,7 @@ export class BundleListComponent implements OnInit {
|
||||
|
||||
list: Bundle[] = [];
|
||||
menuCategories: MenuCategory[] = [];
|
||||
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'info', 'items'];
|
||||
displayedColumns: string[] = ['name', 'price', 'menuCategory', 'saleCategory', 'info', 'items'];
|
||||
|
||||
constructor() {
|
||||
this.form = new FormGroup({
|
||||
@ -91,6 +91,7 @@ export class BundleListComponent implements OnInit {
|
||||
Units: 'units',
|
||||
Price: 'salePrice',
|
||||
MenuCategory: 'menuCategory',
|
||||
SaleCategory: 'saleCategory',
|
||||
Items: 'items',
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { MenuCategory } from '../core/menu-category';
|
||||
import { SaleCategory } from '../core/sale-category';
|
||||
|
||||
export class BundleItem {
|
||||
id?: string;
|
||||
@ -6,12 +7,14 @@ export class BundleItem {
|
||||
name: string;
|
||||
salePrice: number;
|
||||
quantity: number;
|
||||
printInBill: boolean;
|
||||
|
||||
public constructor(init?: Partial<BundleItem>) {
|
||||
this.itemId = '';
|
||||
this.name = '';
|
||||
this.salePrice = 0;
|
||||
this.quantity = 0;
|
||||
this.printInBill = true;
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
@ -30,6 +33,7 @@ export class Bundle {
|
||||
sortOrder: number;
|
||||
|
||||
menuCategory?: MenuCategory | null;
|
||||
saleCategory?: SaleCategory | null;
|
||||
items: BundleItem[];
|
||||
|
||||
public constructor(init?: Partial<Bundle>) {
|
||||
|
||||
@ -2,6 +2,7 @@ import { Routes } from '@angular/router';
|
||||
|
||||
import { authGuard } from '../auth/auth-guard.service';
|
||||
import { menuCategoryListResolver } from '../menu-category/menu-category-list.resolver';
|
||||
import { saleCategoryListResolver } from '../sale-category/sale-category-list.resolver';
|
||||
import { BundleDetailComponent } from './bundle-detail/bundle-detail.component';
|
||||
import { bundleListResolver } from './bundle-list.resolver';
|
||||
import { BundleListComponent } from './bundle-list/bundle-list.component';
|
||||
@ -26,6 +27,7 @@ export const routes: Routes = [
|
||||
resolve: {
|
||||
item: bundleResolver, // returns new Bundle() because id === null (no param here)
|
||||
menuCategories: menuCategoryListResolver,
|
||||
saleCategories: saleCategoryListResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -36,6 +38,7 @@ export const routes: Routes = [
|
||||
resolve: {
|
||||
item: bundleResolver,
|
||||
menuCategories: menuCategoryListResolver,
|
||||
saleCategories: saleCategoryListResolver,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -21,7 +21,6 @@ import { CustomerService } from '../customer.service';
|
||||
styleUrls: ['./customer-detail.component.sass'],
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
|
||||
MatCheckboxModule,
|
||||
MatDividerModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
Reference in New Issue
Block a user