Feature: Added product Stock Keeping Units to prevent duplicate products. A lot of refactoring because of this.
Removed: Reset Stock as it was never used and don't think it is even needed with this new batch system. Fix: Incentive update was not working
This commit is contained in:
@ -0,0 +1,16 @@
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { StockKeepingUnit } from '../../core/product';
|
||||
|
||||
export class ProductDetailDatasource extends DataSource<StockKeepingUnit> {
|
||||
constructor(private data: Observable<StockKeepingUnit[]>) {
|
||||
super();
|
||||
}
|
||||
|
||||
connect(): Observable<StockKeepingUnit[]> {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
disconnect() {}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
<h1 mat-dialog-title>Edit Journal Entry</h1>
|
||||
<div mat-dialog-content>
|
||||
<form [formGroup]="form">
|
||||
<div
|
||||
fxLayout="row wrap"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput placeholder="Units" formControlName="units" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" placeholder="Fraction" formControlName="fraction" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
<input matInput placeholder="Fraction Units" formControlName="fractionUnits" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" placeholder="Yield" formControlName="productYield" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ data.isPurchased ? 'Purchase Price' : 'Cost Price' }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
placeholder="{{ data.isPurchased ? 'Purchase Price' : 'Cost Price' }}"
|
||||
formControlName="price"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex [hidden]="!data.isSold">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="false" cdkFocusInitial>Cancel</button>
|
||||
<button mat-button (click)="accept()" color="primary">Ok</button>
|
||||
</div>
|
||||
@ -0,0 +1,26 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProductDetailDialogComponent } from './product-detail-dialog.component';
|
||||
|
||||
describe('ProductDetailDialogComponent', () => {
|
||||
let component: ProductDetailDialogComponent;
|
||||
let fixture: ComponentFixture<ProductDetailDialogComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProductDetailDialogComponent],
|
||||
}).compileComponents();
|
||||
}),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProductDetailDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,68 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
import { StockKeepingUnit } from '../../core/product';
|
||||
|
||||
@Component({
|
||||
selector: 'app-journal-dialog',
|
||||
templateUrl: './product-detail-dialog.component.html',
|
||||
styleUrls: ['./product-detail-dialog.component.css'],
|
||||
})
|
||||
export class ProductDetailDialogComponent implements OnInit {
|
||||
form: FormGroup;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ProductDetailDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { item: StockKeepingUnit; isSold: boolean; isPurchased: boolean },
|
||||
private fb: FormBuilder,
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
units: '',
|
||||
fraction: '',
|
||||
fractionUnits: '',
|
||||
productYield: '',
|
||||
price: '',
|
||||
salePrice: '',
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form.setValue({
|
||||
units: this.data.item.units,
|
||||
fraction: '' + this.data.item.fraction,
|
||||
fractionUnits: this.data.item.fractionUnits,
|
||||
productYield: '' + this.data.item.productYield,
|
||||
price: '' + this.data.item.price,
|
||||
salePrice: '' + this.data.item.salePrice,
|
||||
});
|
||||
}
|
||||
|
||||
accept(): void {
|
||||
const formValue = this.form.value;
|
||||
const fraction = +formValue.fraction;
|
||||
if (fraction < 1) {
|
||||
return;
|
||||
}
|
||||
const productYield = +formValue.productYield;
|
||||
if (productYield < 0 || productYield > 1) {
|
||||
return;
|
||||
}
|
||||
const price = +formValue.price;
|
||||
if (price < 0) {
|
||||
return;
|
||||
}
|
||||
const salePrice = +formValue.salePrice;
|
||||
if (salePrice < 0) {
|
||||
return;
|
||||
}
|
||||
this.data.item.units = formValue.units;
|
||||
this.data.item.fraction = fraction;
|
||||
this.data.item.fractionUnits = formValue.fractionUnits;
|
||||
this.data.item.productYield = productYield;
|
||||
this.data.item.price = price;
|
||||
this.data.item.salePrice = salePrice;
|
||||
this.dialogRef.close(this.data.item);
|
||||
}
|
||||
}
|
||||
@ -24,55 +24,10 @@
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex="75">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput #nameElement placeholder="Name" formControlName="name" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25">
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput placeholder="Units" formControlName="units" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" placeholder="Fraction" formControlName="fraction" />
|
||||
</mat-form-field>
|
||||
<mat-form-field cdk-overlay-origin="">
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
<input matInput placeholder="Fraction Units" formControlName="fractionUnits" />
|
||||
</mat-form-field>
|
||||
<mat-form-field cdk-overlay-origin="">
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" placeholder="Yield" formControlName="productYield" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
placeholder="{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}"
|
||||
formControlName="price"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex [hidden]="!item.isSold">
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div
|
||||
fxLayout="row"
|
||||
@ -101,7 +56,114 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<h2>Stock Keeping Units</h2>
|
||||
<div
|
||||
formGroupName="addRow"
|
||||
fxLayout="row wrap"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Units</mat-label>
|
||||
<input matInput placeholder="Units" formControlName="units" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction</mat-label>
|
||||
<input matInput type="number" placeholder="Fraction" formControlName="fraction" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Fraction Units</mat-label>
|
||||
<input matInput placeholder="Fraction Units" formControlName="fractionUnits" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Yield</mat-label>
|
||||
<input matInput type="number" placeholder="Yield" formControlName="productYield" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
placeholder="{{ item.isPurchased ? 'Purchase Price' : 'Cost Price' }}"
|
||||
formControlName="price"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>Sale Price</mat-label>
|
||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" (click)="addRow()" fxFlex="15">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
<mat-table [dataSource]="dataSource" aria-label="Elements">
|
||||
<!-- Checkbox Column -->
|
||||
<ng-container matColumnDef="isDefault">
|
||||
<mat-header-cell *matHeaderCellDef>Default</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<mat-checkbox
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="changeDefault($event, row)"
|
||||
[checked]="row.isDefault"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
<!-- Units Column -->
|
||||
<ng-container matColumnDef="units">
|
||||
<mat-header-cell *matHeaderCellDef>Units</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.units }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Fraction Column -->
|
||||
<ng-container matColumnDef="fraction">
|
||||
<mat-header-cell *matHeaderCellDef>Fraction</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.fraction }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Fraction Units Column -->
|
||||
<ng-container matColumnDef="fractionUnits">
|
||||
<mat-header-cell *matHeaderCellDef>Fraction Units</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.fractionUnits }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Yield Column -->
|
||||
<ng-container matColumnDef="yield">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Yield</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.productYield }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Price Column -->
|
||||
<ng-container matColumnDef="price">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Price</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.price | currency: 'INR' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Sale Price Column -->
|
||||
<ng-container matColumnDef="salePrice">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Sale Price</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{
|
||||
row.salePrice | currency: 'INR'
|
||||
}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Action Column -->
|
||||
<ng-container matColumnDef="action">
|
||||
<mat-header-cell *matHeaderCellDef class="center">Action</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="center">
|
||||
<button mat-icon-button tabindex="-1" (click)="editRow(row)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button tabindex="-1" color="warn" (click)="deleteRow(row)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" (click)="save()">Save</button>
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
|
||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { Product } from '../../core/product';
|
||||
import { Product, StockKeepingUnit } from '../../core/product';
|
||||
import { ProductGroup } from '../../core/product-group';
|
||||
import { ToasterService } from '../../core/toaster.service';
|
||||
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { ProductService } from '../product.service';
|
||||
|
||||
import { ProductDetailDatasource } from './product-detail-datasource';
|
||||
import { ProductDetailDialogComponent } from './product-detail-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-detail',
|
||||
templateUrl: './product-detail.component.html',
|
||||
@ -18,8 +23,21 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
|
||||
form: FormGroup;
|
||||
productGroups: ProductGroup[] = [];
|
||||
public skus = new BehaviorSubject<StockKeepingUnit[]>([]);
|
||||
dataSource: ProductDetailDatasource = new ProductDetailDatasource(this.skus);
|
||||
item: Product = new Product();
|
||||
|
||||
displayedColumns = [
|
||||
'isDefault',
|
||||
'units',
|
||||
'fraction',
|
||||
'fractionUnits',
|
||||
'yield',
|
||||
'price',
|
||||
'salePrice',
|
||||
'action',
|
||||
];
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
@ -31,12 +49,14 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form = this.fb.group({
|
||||
code: { value: '', disabled: true },
|
||||
name: '',
|
||||
units: '',
|
||||
fraction: '',
|
||||
fractionUnits: '',
|
||||
productYield: '',
|
||||
price: '',
|
||||
salePrice: '',
|
||||
addRow: this.fb.group({
|
||||
units: '',
|
||||
fraction: '',
|
||||
fractionUnits: '',
|
||||
productYield: '',
|
||||
price: '',
|
||||
salePrice: '',
|
||||
}),
|
||||
isPurchased: '',
|
||||
isSold: '',
|
||||
isActive: '',
|
||||
@ -51,6 +71,8 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
this.productGroups = data.productGroups;
|
||||
this.showItem(data.item);
|
||||
});
|
||||
this.dataSource = new ProductDetailDatasource(this.skus);
|
||||
this.skus.next(this.item.skus);
|
||||
}
|
||||
|
||||
showItem(item: Product) {
|
||||
@ -58,12 +80,14 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
this.form.setValue({
|
||||
code: this.item.code || '(Auto)',
|
||||
name: this.item.name || '',
|
||||
units: this.item.units || '',
|
||||
fraction: this.item.fraction || '',
|
||||
fractionUnits: this.item.fractionUnits || '',
|
||||
productYield: this.item.productYield || '',
|
||||
price: this.item.price || '',
|
||||
salePrice: this.item.salePrice || '',
|
||||
addRow: {
|
||||
units: '',
|
||||
fraction: '',
|
||||
fractionUnits: '',
|
||||
productYield: '',
|
||||
price: '',
|
||||
salePrice: '',
|
||||
},
|
||||
isPurchased: this.item.isPurchased,
|
||||
isSold: this.item.isSold,
|
||||
isActive: this.item.isActive,
|
||||
@ -79,6 +103,79 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
addRow() {
|
||||
const formValue = (this.form.get('addRow') as FormControl).value;
|
||||
const fraction = +formValue.fraction;
|
||||
if (fraction < 1) {
|
||||
this.toaster.show('Danger', 'Fraction has to be >= 1');
|
||||
return;
|
||||
}
|
||||
const productYield = +formValue.productYield;
|
||||
if (productYield < 0 || productYield > 1) {
|
||||
this.toaster.show('Danger', 'Product Yield has to be > 0 and <= 1');
|
||||
return;
|
||||
}
|
||||
const price = +formValue.price;
|
||||
if (price < 0) {
|
||||
this.toaster.show('Danger', 'Price has to be >= 0');
|
||||
return;
|
||||
}
|
||||
const salePrice = +formValue.salePrice;
|
||||
if (salePrice < 0) {
|
||||
this.toaster.show('Danger', 'Sale Price has to be >= 0');
|
||||
return;
|
||||
}
|
||||
this.item.skus.push(
|
||||
new StockKeepingUnit({
|
||||
units: formValue.units,
|
||||
fraction,
|
||||
fractionUnits: formValue.fractionUnits,
|
||||
productYield,
|
||||
price,
|
||||
salePrice,
|
||||
}),
|
||||
);
|
||||
this.skus.next(this.item.skus);
|
||||
this.resetAddRow();
|
||||
}
|
||||
|
||||
resetAddRow() {
|
||||
(this.form.get('addRow') as FormControl).reset({
|
||||
units: '',
|
||||
fraction: '',
|
||||
fractionUnits: '',
|
||||
productYield: '',
|
||||
price: '',
|
||||
salePrice: '',
|
||||
});
|
||||
}
|
||||
|
||||
editRow(row: StockKeepingUnit) {
|
||||
const dialogRef = this.dialog.open(ProductDetailDialogComponent, {
|
||||
width: '750px',
|
||||
data: {
|
||||
item: { ...row },
|
||||
isSold: this.item.isSold,
|
||||
isPurchased: this.item.isPurchased,
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result: boolean | StockKeepingUnit) => {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const j = result as StockKeepingUnit;
|
||||
Object.assign(row, j);
|
||||
this.skus.next(this.item.skus);
|
||||
this.resetAddRow();
|
||||
});
|
||||
}
|
||||
|
||||
deleteRow(row: StockKeepingUnit) {
|
||||
this.item.skus.splice(this.item.skus.indexOf(row), 1);
|
||||
this.skus.next(this.item.skus);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.saveOrUpdate(this.getItem()).subscribe(
|
||||
() => {
|
||||
@ -119,12 +216,6 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
getItem(): Product {
|
||||
const formModel = this.form.value;
|
||||
this.item.name = formModel.name;
|
||||
this.item.units = formModel.units;
|
||||
this.item.fraction = +formModel.fraction;
|
||||
this.item.fractionUnits = formModel.fractionUnits;
|
||||
this.item.productYield = +formModel.productYield;
|
||||
this.item.price = +formModel.price;
|
||||
this.item.salePrice = +formModel.salePrice;
|
||||
this.item.isPurchased = formModel.isPurchased;
|
||||
this.item.isSold = formModel.isSold;
|
||||
this.item.isActive = formModel.isActive;
|
||||
@ -134,4 +225,9 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
||||
this.item.productGroup.id = formModel.productGroup;
|
||||
return this.item;
|
||||
}
|
||||
|
||||
changeDefault($event: MatCheckboxChange, row: StockKeepingUnit) {
|
||||
this.item.skus.forEach((x) => (x.isDefault = false));
|
||||
row.isDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,9 +8,6 @@ import { map, tap } from 'rxjs/operators';
|
||||
import { Product } from '../../core/product';
|
||||
import { ProductGroup } from '../../core/product-group';
|
||||
|
||||
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
|
||||
const compare = (a: string | number, b: string | number, isAsc: boolean) =>
|
||||
(a < b ? -1 : 1) * (isAsc ? 1 : -1);
|
||||
export class ProductListDataSource extends DataSource<Product> {
|
||||
private filterValue = '';
|
||||
|
||||
@ -60,7 +57,7 @@ export class ProductListDataSource extends DataSource<Product> {
|
||||
return this.filterValue.split(' ').reduce(
|
||||
(p: Product[], c: string) =>
|
||||
p.filter((x) => {
|
||||
const productString = `${x.code} ${x.name} ${x.units} ${x.productGroup}${
|
||||
const productString = `${x.code} ${x.name} ${x.productGroup?.name}${
|
||||
x.isPurchased ? ' purchased' : ' made'
|
||||
}${x.isSold ? 'sold' : 'used'}${x.isActive ? 'active' : 'deactive'}`.toLowerCase();
|
||||
return productString.indexOf(c) !== -1;
|
||||
@ -103,3 +100,7 @@ export class ProductListDataSource extends DataSource<Product> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
|
||||
const compare = (a: string | number, b: string | number, isAsc: boolean) =>
|
||||
(a < b ? -1 : 1) * (isAsc ? 1 : -1);
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@ -34,25 +34,41 @@
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"
|
||||
><a [routerLink]="['/products', row.id]"
|
||||
>{{ row.name }} ({{
|
||||
showExtended ? row.fraction + ' ' + row.fractionUnits + ' = 1 ' : ''
|
||||
}}{{ row.units }})</a
|
||||
></mat-cell
|
||||
>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
<li *ngFor="let sku of row.skus">
|
||||
<a [routerLink]="['/products', row.id]"
|
||||
>{{ row.name }} ({{
|
||||
showExtended ? sku.fraction + ' ' + sku.fractionUnits + ' = 1 ' : ''
|
||||
}}{{ sku.units }})</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Cost Price Column -->
|
||||
<ng-container matColumnDef="costPrice">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Cost Price</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.price | currency: 'INR' }}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
<li *ngFor="let sku of row.skus">
|
||||
{{ sku.price | currency: 'INR' }}
|
||||
</li>
|
||||
</ul>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Yield Column -->
|
||||
<ng-container matColumnDef="productYield">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Yield</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.productYield | percent: '1.2-2' }}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<ul>
|
||||
<li *ngFor="let sku of row.skus">
|
||||
{{ sku.productYield | percent: '1.2-2' }}
|
||||
</li>
|
||||
</ul>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Product Group Column -->
|
||||
|
||||
@ -27,11 +27,10 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||
displayedColumns: string[] = [];
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
private _showExtended = false;
|
||||
private _showExtended = true;
|
||||
|
||||
constructor(private route: ActivatedRoute, private fb: FormBuilder, private toCsv: ToCsvService) {
|
||||
this.showExtended = false;
|
||||
this.showExtended = true;
|
||||
this.form = this.fb.group({
|
||||
filter: '',
|
||||
});
|
||||
@ -44,12 +43,10 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
get showExtended(): boolean {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
return this._showExtended;
|
||||
}
|
||||
|
||||
set showExtended(value: boolean) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
this._showExtended = value;
|
||||
if (value) {
|
||||
this.displayedColumns = ['name', 'costPrice', 'productYield', 'productGroup', 'info'];
|
||||
@ -76,7 +73,6 @@ export class ProductListComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
exportCsv() {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const headers = {
|
||||
Code: 'code',
|
||||
Name: 'name',
|
||||
|
||||
@ -7,6 +7,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatOptionModule } from '@angular/material/core';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
@ -15,6 +16,7 @@ import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
import { ProductDetailDialogComponent } from './product-detail/product-detail-dialog.component';
|
||||
import { ProductDetailComponent } from './product-detail/product-detail.component';
|
||||
import { ProductListComponent } from './product-list/product-list.component';
|
||||
import { ProductRoutingModule } from './product-routing.module';
|
||||
@ -37,7 +39,8 @@ import { ProductRoutingModule } from './product-routing.module';
|
||||
MatCheckboxModule,
|
||||
ReactiveFormsModule,
|
||||
ProductRoutingModule,
|
||||
MatDialogModule,
|
||||
],
|
||||
declarations: [ProductListComponent, ProductDetailComponent],
|
||||
declarations: [ProductListComponent, ProductDetailComponent, ProductDetailDialogComponent],
|
||||
})
|
||||
export class ProductModule {}
|
||||
|
||||
@ -54,10 +54,13 @@ export class ProductService {
|
||||
autocomplete(
|
||||
query: string,
|
||||
extended: boolean = false,
|
||||
skus: boolean = true,
|
||||
date?: string,
|
||||
vendorId?: string,
|
||||
): Observable<Product[]> {
|
||||
const options = { params: new HttpParams().set('q', query).set('e', extended.toString()) };
|
||||
const options = {
|
||||
params: new HttpParams().set('q', query).set('e', extended.toString()).set('s', skus),
|
||||
};
|
||||
if (!!vendorId && !!date) {
|
||||
options.params = options.params.set('v', vendorId as string).set('d', date as string);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user