Fully working with the rule no explicit any

This commit is contained in:
2020-11-25 09:27:42 +05:30
parent 84535ca9bb
commit b583b90756
27 changed files with 223 additions and 155 deletions

View File

@ -38,6 +38,6 @@ module.exports = {
"@typescript-eslint/lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
"class-methods-use-this": ["error", {"exceptMethods": ["disconnect", "displayFn", "transform"]}],
"import/order": ["error", {"alphabetize": {"order": "asc", "caseInsensitive": true}, "newlines-between": "always"}],
"@typescript-eslint/no-explicit-any": "off", // Disabled for now, but needed to transition to strict compiling
"@typescript-eslint/no-explicit-any": "error",
}
};

View File

@ -89,7 +89,7 @@ export class AuthService {
formData.append('otp', otp);
formData.append('grant_type', 'password');
return this.http
.post<any>(loginUrl, formData)
.post<{ access_token: string; token_type: string }>(loginUrl, formData)
.pipe(map((u) => u.access_token))
.pipe(map((u) => AuthService.parseJwt(u)))
.pipe(
@ -118,7 +118,7 @@ export class AuthService {
refreshToken() {
return this.http
.post<any>(refreshUrl, {})
.post<{ access_token: string; token_type: string }>(refreshUrl, {})
.pipe(map((u) => u.access_token))
.pipe(map((u) => AuthService.parseJwt(u)))
.pipe(

View File

@ -70,14 +70,16 @@ export class CashierReportComponent implements OnInit {
}
print() {
this.ser.print(this.info.cashier.id as string, this.info.startDate, this.info.finishDate).subscribe(
() => {
this.toaster.show('', 'Successfully Printed');
},
(error) => {
this.toaster.show('Error', error.error);
},
);
this.ser
.print(this.info.cashier.id as string, this.info.startDate, this.info.finishDate)
.subscribe(
() => {
this.toaster.show('', 'Successfully Printed');
},
(error) => {
this.toaster.show('Error', error.error);
},
);
}
getInfo(): CashierReport {

View File

@ -3,9 +3,8 @@ import { Product } from './product';
import { Tax } from './tax';
export class BillViewItem {
id: string;
id: string | undefined;
isKot: boolean;
oldKot: boolean;
info: string;
kotId: string;
@ -20,10 +19,16 @@ export class BillViewItem {
tax: Tax;
modifiers: Modifier[];
public get isOldKot(): boolean {
return this.isKot && this.id !== undefined;
}
public get isNewKot(): boolean {
return this.isKot && this.id === undefined;
}
public constructor(init?: Partial<BillViewItem>) {
this.id = '';
this.isKot = true;
this.oldKot = false;
this.info = '';
this.kotId = '';
this.product = new Product();

View File

@ -19,7 +19,7 @@ export class ErrorLoggerService {
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
public handleError<T>(serviceName = 'error-logger', operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
return (error: unknown): Observable<T> => {
ErrorLoggerService.log(serviceName, `${operation} failed: ${error}`);
return throwError(error);
};

View File

@ -19,7 +19,7 @@ export class ErrorInterceptor implements HttpInterceptor {
private toaster: ToasterService,
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
catchError((err) => {
// We don't want to refresh token for some requests like login or refresh token itself

View File

@ -10,7 +10,7 @@ export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// add authorization header with jwt token if available
// We use this line to debug token refreshing

View File

@ -1,6 +1,7 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatSelectChange } from '@angular/material/select';
import { ActivatedRoute, Router } from '@angular/router';
import { map } from 'rxjs/operators';
@ -74,7 +75,7 @@ export class HeaderFooterComponent implements OnInit {
return item;
}
show(val: any) {
show(val: MatSelectChange) {
this.router.navigate(['/header-footer', val.value]);
}
}

View File

@ -4,6 +4,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatTreeNestedDataSource } from '@angular/material/tree';
import { ActivatedRoute, Router } from '@angular/router';
import { map } from 'rxjs/operators';
import { MenuCategory } from '../../core/menu-category';
import { ModifierCategory } from '../../core/modifier-category';
@ -11,6 +12,7 @@ import { Product } from '../../core/product';
import { ToasterService } from '../../core/toaster.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
import { ModifierCategoryService } from '../modifier-category.service';
import { NodeItem } from '../node-item';
@Component({
selector: 'app-role-detail',
@ -21,8 +23,8 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
@ViewChild('nameElement', { static: true }) nameElement?: ElementRef;
form: FormGroup;
item: ModifierCategory = new ModifierCategory();
treeControl = new NestedTreeControl<any>((node) => node.products);
dataSource = new MatTreeNestedDataSource<any>();
treeControl = new NestedTreeControl<NodeItem>((node: NodeItem) => node.children);
dataSource = new MatTreeNestedDataSource<NodeItem>();
products: Map<string, Product> = new Map<string, Product>();
productsOfMenuCategory: Map<string, Product[]> = new Map<string, Product[]>();
@ -45,15 +47,26 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
}
ngOnInit() {
this.route.data.subscribe((value) => {
const data = value as { item: ModifierCategory };
this.showItem(data.item);
});
this.route.data
.pipe(
map((value) => {
const data = value as { item: ModifierCategory };
const tree: NodeItem[] = data.item.menuCategories.map((x: MenuCategory) => ({
id: x.id as string,
name: x.name,
children: x.products.map((y: Product) => ({ id: y.id as string, name: y.name })),
}));
return { item: data.item, tree };
}),
)
.subscribe((data) => {
this.showItem(data.item, data.tree);
});
}
showItem(item: ModifierCategory) {
showItem(item: ModifierCategory, tree: NodeItem[]) {
this.item = item;
this.dataSource.data = item.menuCategories;
this.dataSource.data = tree;
this.form.patchValue({
name: this.item.name || '',
minimum: `${this.item.minimum}`,
@ -133,22 +146,22 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
return this.item;
}
hasChild = (_: number, node: any) => !!node.products && node.products.length > 0;
hasChild = (_: number, node: NodeItem) => !!node.children && node.children.length > 0;
isProductSelected(node: Product) {
return (this.products.get(node.id as string) as Product).enabled;
isProductSelected(node: NodeItem) {
return (this.products.get(node.id) as Product).enabled;
}
isMenuCategorySelected(node: MenuCategory) {
return (this.productsOfMenuCategory.get(node.id as string) as Product[]).reduce(
isMenuCategorySelected(node: NodeItem) {
return (this.productsOfMenuCategory.get(node.id) as Product[]).reduce(
(acc: boolean, current: Product) => acc && current.enabled,
true,
);
}
isMenuCategoryPartiallySelected(node: MenuCategory) {
const total = (this.productsOfMenuCategory.get(node.id as string) as Product[]).length;
const ticked = (this.productsOfMenuCategory.get(node.id as string) as Product[]).reduce(
isMenuCategoryPartiallySelected(node: NodeItem) {
const total = (this.productsOfMenuCategory.get(node.id) as Product[]).length;
const ticked = (this.productsOfMenuCategory.get(node.id) as Product[]).reduce(
(acc, current) => {
if (current.enabled) {
// eslint-disable-next-line no-param-reassign
@ -161,12 +174,12 @@ export class ModifierCategoryDetailComponent implements OnInit, AfterViewInit {
return ticked > 0 && ticked < total;
}
toggleProductSelection(node: Product) {
(this.products.get(node.id as string) as Product).enabled = !(this.products.get(node.id as string) as Product)
toggleProductSelection(node: NodeItem) {
(this.products.get(node.id) as Product).enabled = !(this.products.get(node.id) as Product)
.enabled;
}
toggleMenuCategorySelection(node: MenuCategory) {
toggleMenuCategorySelection(node: NodeItem) {
const sel = !this.isMenuCategorySelected(node);
(this.productsOfMenuCategory.get(node.id as string) as Product[]).forEach((p) => {
p.enabled = sel;

View File

@ -0,0 +1,5 @@
export interface NodeItem {
id: string;
name: string;
children?: NodeItem[];
}

View File

@ -1,5 +1,6 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
@ -34,7 +35,7 @@ export class ModifierListComponent implements OnInit {
});
}
filterOn(val: any) {
filterOn(val: MatSelectChange) {
this.filter.next(val.value);
}

View File

@ -20,9 +20,9 @@ export class BillTypeComponent {
}
accept(): void {
if (this.selected === 'REGULAR_BILL') this.dialogRef.close(VoucherType.Bill)
else if (this.selected === 'STAFF') this.dialogRef.close(VoucherType.Staff)
else if (this.selected === 'NO_CHARGE') this.dialogRef.close(VoucherType.NoCharge)
if (this.selected === 'REGULAR_BILL') this.dialogRef.close(VoucherType.Bill);
else if (this.selected === 'STAFF') this.dialogRef.close(VoucherType.Staff);
else if (this.selected === 'NO_CHARGE') this.dialogRef.close(VoucherType.NoCharge);
else this.dialogRef.close();
}
}

View File

@ -21,14 +21,14 @@ import { ModifiersComponent } from './modifiers/modifiers.component';
@Injectable()
export class BillService {
public dataObs;
public data: any[];
public dataObs: BehaviorSubject<BillViewItem[]>;
public data: BillViewItem[];
public bill: Bill = new Bill();
public netAmount: BehaviorSubject<number>;
public discountAmount: BehaviorSubject<number>;
public taxAmount: BehaviorSubject<number>;
public amount: BehaviorSubject<number>;
public selection = new SelectionModel<any>(true, []);
public selection = new SelectionModel<BillViewItem>(true, []);
constructor(
private dialog: MatDialog,
@ -37,7 +37,7 @@ export class BillService {
private modifierCategoryService: ModifierCategoryService,
) {
this.data = [];
this.dataObs = new BehaviorSubject<any[]>(this.data);
this.dataObs = new BehaviorSubject<BillViewItem[]>(this.data);
this.netAmount = new BehaviorSubject(0);
this.discountAmount = new BehaviorSubject(0);
this.taxAmount = new BehaviorSubject(0);
@ -50,7 +50,6 @@ export class BillService {
new BillViewItem({
id: k.id,
isKot: true,
oldKot: true,
info: `Kot: ${k.code} / ${k.date} (${k.user.name}) `,
}),
...k.inventories.map(
@ -74,7 +73,7 @@ export class BillService {
),
]);
this.data = view.reduce((a, c) => a.concat(c), []);
this.data.push({ isKot: true, newKot: true, info: '== New Kot ==' });
this.data.push(new BillViewItem({ isKot: true, info: '== New Kot ==' }));
this.dataObs.next(this.data);
this.updateAmounts();
}
@ -101,7 +100,7 @@ export class BillService {
if (old !== undefined) {
old.quantity += quantity;
} else {
const item = {
const item = new BillViewItem({
isKot: false,
product,
productId: product.id,
@ -113,11 +112,11 @@ export class BillService {
taxRate: product.tax.rate,
tax: product.tax,
modifiers: [],
};
});
this.data.push(item);
this.modifierCategoryService.listForProduct(product.id as string).subscribe((result) => {
if (
result.reduce((a: any, c: ModifierCategory) => {
result.reduce((a: number, c: ModifierCategory) => {
return a + c.minimum;
}, 0)
) {
@ -129,14 +128,14 @@ export class BillService {
this.updateAmounts();
}
showModifier(item: any): void {
showModifier(item: BillViewItem): void {
// [routerLink]="['/sales', 'modifiers', item.id]"
const dialogRef = this.dialog.open(ModifiersComponent, {
position: {
top: '10vh',
},
data: {
list: this.modifierCategoryService.listForProduct(item.productId),
list: this.modifierCategoryService.listForProduct(item.productId as string),
selected: item.modifiers,
},
});
@ -148,20 +147,23 @@ export class BillService {
});
}
addOne(item: any): void {
addOne(item: BillViewItem): void {
item.quantity += 1;
this.dataObs.next(this.data);
this.updateAmounts();
}
quantity(item: any, quantity: number): void {
quantity(item: BillViewItem, quantity: number): void {
item.quantity = quantity;
this.dataObs.next(this.data);
this.updateAmounts();
}
subtractOne(item: any, canEdit: boolean): void {
if (item.quantity > 1 || (canEdit && this.minimum(item.productId, item.isHappyHour) >= 1)) {
subtractOne(item: BillViewItem, canEdit: boolean): void {
if (
item.quantity > 1 ||
(canEdit && this.minimum(item.productId as string, item.isHappyHour) >= 1)
) {
item.quantity -= 1;
this.dataObs.next(this.data);
this.updateAmounts();
@ -170,13 +172,13 @@ export class BillService {
}
}
removeItem(item: any): void {
removeItem(item: BillViewItem): void {
this.data.splice(this.data.indexOf(item), 1);
this.dataObs.next(this.data);
this.updateAmounts();
}
modifier(item: any): void {
modifier(item: BillViewItem): void {
this.showModifier(item);
}
@ -230,7 +232,7 @@ export class BillService {
const item = JSON.parse(JSON.stringify(this.bill));
item.kots.forEach((k: Kot) => {
k.inventories.forEach((i: Inventory) => {
i.discount = this.data.find((x) => !x.isKot && x.id === i.id).discount;
i.discount = (this.data.find((x) => !x.isKot && x.id === i.id) as BillViewItem).discount;
});
});
item.kots.push(this.getKot());
@ -273,7 +275,10 @@ export class BillService {
math.round(
this.data
.filter((x) => !x.isKot)
.reduce((ca: number, c: any) => ca + (c.isHappyHour ? 0 : c.price) * c.quantity, 0),
.reduce(
(ca: number, c: BillViewItem) => ca + (c.isHappyHour ? 0 : c.price) * c.quantity,
0,
),
),
);
this.discountAmount.next(
@ -281,7 +286,7 @@ export class BillService {
this.data
.filter((x) => !x.isKot)
.reduce(
(ca: number, c: Inventory) =>
(ca: number, c: BillViewItem) =>
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount,
0,
),
@ -292,7 +297,7 @@ export class BillService {
this.data
.filter((x) => !x.isKot)
.reduce(
(ca: number, c: Inventory) =>
(ca: number, c: BillViewItem) =>
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate,
0,
),
@ -303,7 +308,7 @@ export class BillService {
this.data
.filter((x) => !x.isKot)
.reduce(
(ca: number, c: Inventory) =>
(ca: number, c: BillViewItem) =>
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
0,
),
@ -327,7 +332,9 @@ export class BillService {
}
splitBill(table: Table): Observable<boolean> {
const inventoriesToMove: string[] = this.selection.selected.map((x: any) => x.id);
const inventoriesToMove: string[] = this.selection.selected.map(
(x: BillViewItem) => x.id as string,
);
return this.ser.splitBill(this.bill.id as string, inventoriesToMove, table);
}
}

View File

@ -16,12 +16,12 @@ export class Bill {
kotId: string;
table: Table;
guest: GuestBook;
settlements: any[];
// settlements: any[];
voidReason: string;
voucherType: string;
serial: number;
kots: Kot[];
reprints: any[];
// reprints: any[];
get dateTip(): string {
return this.date;
@ -46,12 +46,12 @@ export class Bill {
this.kotId = '';
this.table = new Table();
this.guest = new GuestBook();
this.settlements = [];
// this.settlements = [];
this.voidReason = '';
this.voucherType = '';
this.serial = 0;
this.kots = [];
this.reprints = [];
// this.reprints = [];
Object.assign(this, init);
}
}

View File

@ -1,12 +1,14 @@
import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs';
export class BillsDataSource extends DataSource<any> {
constructor(private data: Observable<any[]>) {
import { BillViewItem } from '../../core/bill-view-item';
export class BillsDataSource extends DataSource<BillViewItem> {
constructor(private data: Observable<BillViewItem[]>) {
super();
}
connect(): Observable<any[]> {
connect(): Observable<BillViewItem[]> {
return this.data;
}

View File

@ -52,7 +52,7 @@
<ng-container matColumnDef="select">
<mat-cell *matCellDef="let row">
<mat-checkbox
*ngIf="row.oldKot"
*ngIf="row.isOldKot"
(change)="$event ? masterToggle(row) : null"
[checked]="bs.selection.hasValue() && isAllSelected(row)"
[indeterminate]="isAnySelected(row)"
@ -70,7 +70,7 @@
</ng-container>
<!-- Info Column -->
<ng-container matColumnDef="info">
<mat-cell *matCellDef="let row" [class.blue800]="row.newKot">
<mat-cell *matCellDef="let row" [class.blue800]="row.isNewKot">
<span>
{{ row.info }}
</span>
@ -123,7 +123,12 @@
>
<mat-icon class="del">assignment</mat-icon>
</button>
<button mat-icon-button (click)="moveKot(row)" [disabled]="row.newKot" *ngIf="row.isKot">
<button
mat-icon-button
(click)="moveKot(row)"
[disabled]="row.isKot && !row.id"
*ngIf="row.isKot"
>
<mat-icon class="del">open_in_new</mat-icon>
</button>
</mat-cell>
@ -166,8 +171,8 @@
<mat-header-row *matHeaderRowDef="['table-title', 'table-details']"></mat-header-row>
<mat-row
*matRowDef="let row; columns: displayedColumns"
[class.blue400]="row.oldKot"
[class.blue800]="row.newKot"
[class.blue400]="row.isOldKot"
[class.blue800]="row.isNewKot"
[class.red100]="row.isPrinted"
></mat-row>
<mat-footer-row *matFooterRowDef="['net-title', 'net-amount']"></mat-footer-row>

View File

@ -5,6 +5,7 @@ import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AuthService } from '../../auth/auth.service';
import { BillViewItem } from '../../core/bill-view-item';
import { Table } from '../../core/table';
import { ToasterService } from '../../core/toaster.service';
import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component';
@ -68,7 +69,7 @@ export class BillsComponent implements OnInit {
isAllSelected(kot: Kot) {
return this.bs.data
.filter((x) => x.kotId === kot.id)
.reduce((p: boolean, c: any) => p && this.bs.selection.isSelected(c), true);
.reduce((p: boolean, c: BillViewItem) => p && this.bs.selection.isSelected(c), true);
}
isAnySelected(kot: Kot) {
@ -76,7 +77,7 @@ export class BillsComponent implements OnInit {
let found = 0;
this.bs.data
.filter((x) => x.kotId === kot.id)
.forEach((c: any) => {
.forEach((c: BillViewItem) => {
total += 1;
if (this.bs.selection.isSelected(c)) {
found += 1;
@ -94,11 +95,11 @@ export class BillsComponent implements OnInit {
);
}
addOne(item: any): void {
addOne(item: BillViewItem): void {
this.bs.addOne(item);
}
quantity(item: any): void {
quantity(item: BillViewItem): void {
const dialogRef = this.dialog.open(QuantityComponent, {
// width: '750px',
data: item.quantity,
@ -123,16 +124,16 @@ export class BillsComponent implements OnInit {
});
}
subtractOne(item: any): void {
subtractOne(item: BillViewItem): void {
const canEdit = this.auth.allowed('edit-printed-product');
this.bs.subtractOne(item, canEdit);
}
removeItem(item: any): void {
removeItem(item: BillViewItem): void {
this.bs.removeItem(item);
}
modifier(item: any): void {
modifier(item: BillViewItem): void {
this.bs.modifier(item);
}
@ -202,7 +203,7 @@ export class BillsComponent implements OnInit {
);
}
rowQuantityDisabled(row: any) {
rowQuantityDisabled(row: BillViewItem) {
if (!row.isPrinted) {
return false;
}

View File

@ -11,7 +11,7 @@ import { DiscountDataSource } from './discount-datasource';
styleUrls: ['./discount.component.css'],
})
export class DiscountComponent {
list: any[] = [];
list: { name: string; discount: number }[] = [];
form: FormGroup;
dataSource: DiscountDataSource = new DiscountDataSource([]);
@ -20,12 +20,12 @@ export class DiscountComponent {
constructor(
public dialogRef: MatDialogRef<DiscountComponent>,
private fb: FormBuilder,
@Inject(MAT_DIALOG_DATA) public data: Observable<any[]>,
@Inject(MAT_DIALOG_DATA) public data: Observable<{ name: string; discount: number }[]>,
) {
this.form = this.fb.group({
discounts: '',
});
this.data.subscribe((list: any[]) => {
this.data.subscribe((list: { name: string; discount: number }[]) => {
this.list = list;
this.form.setControl(
'discounts',

View File

@ -249,7 +249,7 @@ export class SalesHomeComponent {
}
const amount = this.bs.amountVal();
const type = this.bs.type();
let obs: any;
let obs: Observable<boolean>;
if (type === 'NO_CHARGE' || type === 'STAFF') {
obs = this.receivePaymentWithReason(type, amount);
} else {

View File

@ -1,6 +1,7 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatSelectChange } from '@angular/material/select';
import { ActivatedRoute, Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
@ -127,7 +128,7 @@ export class SectionPrinterComponent implements OnInit {
return this.list;
}
show(val: any) {
show(val: MatSelectChange) {
this.router.navigate(['/section-printers', val.value]);
}
}

View File

@ -4,7 +4,8 @@ import { Pipe, PipeTransform } from '@angular/core';
name: 'clear',
})
export class ClearPipe implements PipeTransform {
transform(value: any): any {
transform(value: string | null): string {
if (value === null) return '';
return value === '₹ 0.00' || value === '0.00' ? '' : value;
}
}

View File

@ -9,6 +9,6 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
export class ConfirmDialogComponent {
constructor(
public dialogRef: MatDialogRef<ConfirmDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
@Inject(MAT_DIALOG_DATA) public data: { title: string; content: string },
) {}
}

View File

@ -9,7 +9,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
export class ImageDialogComponent {
constructor(
public dialogRef: MatDialogRef<ImageDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
@Inject(MAT_DIALOG_DATA) public data: string,
) {}
close(): void {

View File

@ -5,16 +5,6 @@ import { evaluate, round } from 'mathjs';
providedIn: 'root',
})
export class MathService {
// eslint-disable-next-line class-methods-use-this
journalAmount(amount: string = '', debit: number): any {
const val = this.parseAmount(amount, 2);
let newDebit = debit;
if (val < 0) {
newDebit *= -1;
}
return { debit: newDebit, amount: Math.abs(val) };
}
// eslint-disable-next-line class-methods-use-this
parseAmount(amount: string = '', rounding: number = 2): number {
const cleaned = `${amount}`.replace(new RegExp('(₹[s]*)|(,)|(s)', 'g'), '');

View File

@ -0,0 +1,3 @@
export interface ToCsvType {
[column: string]: string | number | boolean | null;
}

View File

@ -1,15 +1,19 @@
import { Injectable } from '@angular/core';
import { ToCsvType } from './to-csv-type';
@Injectable({
providedIn: 'root',
})
export class ToCsvService {
// eslint-disable-next-line class-methods-use-this
toCsv(headers: any, data: any[]): string {
toCsv(headers: { [display: string]: string }, data: unknown[]): string {
const header = Object.keys(headers);
const replacer = (key: string, value: string | number | null) => (value === null ? '' : value);
const csv = data.map((row) =>
header.map((fieldName) => JSON.stringify(row[headers[fieldName]], replacer)).join(','),
header
.map((fieldName) => JSON.stringify((row as ToCsvType)[headers[fieldName]], replacer))
.join(','),
);
csv.unshift(header.join(','));
return csv.join('\r\n');