Moved from tslint to eslint as tslint was depreciated.
Added prettier and also prettied all the typescript files using prettier ESLint is using the AirBnB rules which are the most strict to lint the files.
This commit is contained in:
@ -1,10 +1,8 @@
|
||||
import {DataSource} from '@angular/cdk/collections';
|
||||
import {Observable} from 'rxjs';
|
||||
import {Inventory, Journal} from '../core/voucher';
|
||||
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Inventory, Journal } from '../core/voucher';
|
||||
|
||||
export class IssueDataSource extends DataSource<Inventory> {
|
||||
|
||||
constructor(private data: Observable<Inventory[]>) {
|
||||
super();
|
||||
}
|
||||
@ -13,6 +11,5 @@ export class IssueDataSource extends DataSource<Inventory> {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
@ -1,19 +1,43 @@
|
||||
<h1 mat-dialog-title>Edit Issue Entry</h1>
|
||||
<div mat-dialog-content>
|
||||
<form [formGroup]="form">
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex="65">
|
||||
<input type="text" matInput placeholder="Product" #batchElement [matAutocomplete]="autoB"
|
||||
formControlName="batch" autocomplete="off">
|
||||
<mat-autocomplete #autoB="matAutocomplete" autoActiveFirstOption [displayWith]="displayBatchName"
|
||||
(optionSelected)="batchSelected($event)">
|
||||
<mat-option *ngFor="let batch of batches | async" [value]="batch">{{batch.name}}</mat-option>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="Product"
|
||||
#batchElement
|
||||
[matAutocomplete]="autoB"
|
||||
formControlName="batch"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#autoB="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayBatchName"
|
||||
(optionSelected)="batchSelected($event)"
|
||||
>
|
||||
<mat-option *ngFor="let batch of batches | async" [value]="batch">{{
|
||||
batch.name
|
||||
}}</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="35">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input type="text" matInput placeholder="Quantity" formControlName="quantity" autocomplete="off">
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="Quantity"
|
||||
formControlName="quantity"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
@ -22,4 +46,3 @@
|
||||
<button mat-button [mat-dialog-close]="false" cdkFocusInitial>Cancel</button>
|
||||
<button mat-button (click)="accept()" color="primary">Ok</button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -8,9 +8,8 @@ describe('IssueDialogComponent', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ IssueDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
declarations: [IssueDialogComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import {Component, Inject, OnInit} from '@angular/core';
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import {FormBuilder, FormGroup} from '@angular/forms';
|
||||
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
||||
import {Observable, of as observableOf} from 'rxjs';
|
||||
import {Batch} from '../core/voucher';
|
||||
import {BatchService} from '../core/batch.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { debounceTime, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Batch } from '../core/voucher';
|
||||
import { BatchService } from '../core/batch.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-issue-dialog',
|
||||
templateUrl: './issue-dialog.component.html',
|
||||
styleUrls: ['./issue-dialog.component.css']
|
||||
styleUrls: ['./issue-dialog.component.css'],
|
||||
})
|
||||
export class IssueDialogComponent implements OnInit {
|
||||
batches: Observable<Batch[]>;
|
||||
@ -21,7 +21,8 @@ export class IssueDialogComponent implements OnInit {
|
||||
public dialogRef: MatDialogRef<IssueDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private fb: FormBuilder,
|
||||
private batchSer: BatchService) {
|
||||
private batchSer: BatchService,
|
||||
) {
|
||||
this.createForm();
|
||||
this.listenToBatchAutocompleteChange();
|
||||
}
|
||||
@ -29,7 +30,7 @@ export class IssueDialogComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
this.form.setValue({
|
||||
batch: this.data.inventory.batch,
|
||||
quantity: this.data.inventory.quantity
|
||||
quantity: this.data.inventory.quantity,
|
||||
});
|
||||
this.batch = this.data.inventory.batch;
|
||||
}
|
||||
@ -37,19 +38,21 @@ export class IssueDialogComponent implements OnInit {
|
||||
createForm() {
|
||||
this.form = this.fb.group({
|
||||
batch: '',
|
||||
quantity: ''
|
||||
quantity: '',
|
||||
});
|
||||
}
|
||||
|
||||
listenToBatchAutocompleteChange(): void {
|
||||
const control = this.form.get('batch');
|
||||
this.batches = control.valueChanges
|
||||
.pipe(
|
||||
startWith(null),
|
||||
map(x => (x !== null && x.length >= 1) ? x : null),
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
switchMap(x => (x === null) ? observableOf([]) : this.batchSer.autocomplete(this.data.date, x)));
|
||||
this.batches = control.valueChanges.pipe(
|
||||
startWith(null),
|
||||
map((x) => (x !== null && x.length >= 1 ? x : null)),
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
switchMap((x) =>
|
||||
x === null ? observableOf([]) : this.batchSer.autocomplete(this.data.date, x),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
displayBatchName(batch?: Batch): string | undefined {
|
||||
@ -62,14 +65,15 @@ export class IssueDialogComponent implements OnInit {
|
||||
|
||||
accept(): void {
|
||||
const formValue = this.form.value;
|
||||
const quantity = +(formValue.quantity);
|
||||
const quantity = +formValue.quantity;
|
||||
this.data.inventory.batch = this.batch;
|
||||
this.data.inventory.product = this.batch.product;
|
||||
this.data.inventory.quantity = quantity;
|
||||
this.data.inventory.rate = this.batch.rate;
|
||||
this.data.inventory.tax = this.batch.tax;
|
||||
this.data.inventory.discount = this.batch.discount;
|
||||
this.data.inventory.amount = quantity * this.batch.rate * (1 + this.batch.tax) * (1 - this.batch.discount);
|
||||
this.data.inventory.amount =
|
||||
quantity * this.batch.rate * (1 + this.batch.tax) * (1 - this.batch.discount);
|
||||
this.dialogRef.close(this.data.inventory);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import {DataSource} from '@angular/cdk/collections';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
import { DataSource } from '@angular/cdk/collections';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export class IssueGridDataSource extends DataSource<any> {
|
||||
|
||||
constructor(private data: Observable<any[]>) {
|
||||
super();
|
||||
}
|
||||
@ -12,6 +10,5 @@ export class IssueGridDataSource extends DataSource<any> {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import { IssueGridService } from './issue-grid.service';
|
||||
describe('IssueGridService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [IssueGridService]
|
||||
providers: [IssueGridService],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -8,17 +8,16 @@ const url = '/api/issue-grid';
|
||||
const serviceName = 'IssueGridService';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class IssueGridService {
|
||||
|
||||
constructor(private http: HttpClient, private log: ErrorLoggerService) {
|
||||
}
|
||||
constructor(private http: HttpClient, private log: ErrorLoggerService) {}
|
||||
|
||||
issueGrid(date: string): Observable<any[]> {
|
||||
return <Observable<any[]>>this.http.get<any[]>(`${url}/${date}`)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'autocomplete'))
|
||||
);
|
||||
return <Observable<any[]>>(
|
||||
this.http
|
||||
.get<any[]>(`${url}/${date}`)
|
||||
.pipe(catchError(this.log.handleError(serviceName, 'autocomplete')))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {IssueResolver} from './issue-resolver.service';
|
||||
import { IssueResolver } from './issue-resolver.service';
|
||||
|
||||
describe('IssueResolver', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [IssueResolver]
|
||||
providers: [IssueResolver],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,16 +1,14 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router';
|
||||
import {Observable} from 'rxjs/internal/Observable';
|
||||
import {Voucher} from '../core/voucher';
|
||||
import {VoucherService} from '../core/voucher.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { Voucher } from '../core/voucher';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class IssueResolver implements Resolve<Voucher> {
|
||||
|
||||
constructor(private ser: VoucherService) {
|
||||
}
|
||||
constructor(private ser: VoucherService) {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Voucher> {
|
||||
const id = route.paramMap.get('id');
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {IssueRoutingModule} from './issue-routing.module';
|
||||
import { IssueRoutingModule } from './issue-routing.module';
|
||||
|
||||
describe('IssueRoutingModule', () => {
|
||||
let issueRoutingModule: IssueRoutingModule;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {IssueResolver} from './issue-resolver.service';
|
||||
import {AuthGuard} from '../auth/auth-guard.service';
|
||||
import {IssueComponent} from './issue.component';
|
||||
import {CostCentreListResolver} from '../cost-centre/cost-centre-list-resolver.service';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { IssueResolver } from './issue-resolver.service';
|
||||
import { AuthGuard } from '../auth/auth-guard.service';
|
||||
import { IssueComponent } from './issue.component';
|
||||
import { CostCentreListResolver } from '../cost-centre/cost-centre-list-resolver.service';
|
||||
|
||||
const issueRoutes: Routes = [
|
||||
{
|
||||
@ -12,41 +12,32 @@ const issueRoutes: Routes = [
|
||||
component: IssueComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
permission: 'Issue'
|
||||
permission: 'Issue',
|
||||
},
|
||||
resolve: {
|
||||
voucher: IssueResolver,
|
||||
costCentres: CostCentreListResolver
|
||||
costCentres: CostCentreListResolver,
|
||||
},
|
||||
runGuardsAndResolvers: 'always'
|
||||
runGuardsAndResolvers: 'always',
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: IssueComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
permission: 'Issue'
|
||||
permission: 'Issue',
|
||||
},
|
||||
resolve: {
|
||||
voucher: IssueResolver,
|
||||
costCentres: CostCentreListResolver
|
||||
costCentres: CostCentreListResolver,
|
||||
},
|
||||
runGuardsAndResolvers: 'always'
|
||||
}
|
||||
runGuardsAndResolvers: 'always',
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild(issueRoutes)
|
||||
|
||||
],
|
||||
exports: [
|
||||
RouterModule
|
||||
],
|
||||
providers: [
|
||||
IssueResolver
|
||||
]
|
||||
imports: [CommonModule, RouterModule.forChild(issueRoutes)],
|
||||
exports: [RouterModule],
|
||||
providers: [IssueResolver],
|
||||
})
|
||||
export class IssueRoutingModule {
|
||||
}
|
||||
export class IssueRoutingModule {}
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
}
|
||||
|
||||
.selected {
|
||||
background: #fff3cd
|
||||
background: #fff3cd;
|
||||
}
|
||||
|
||||
.unposted {
|
||||
background: #f8d7da
|
||||
background: #f8d7da;
|
||||
}
|
||||
|
||||
.center {
|
||||
|
||||
@ -4,11 +4,23 @@
|
||||
</mat-card-title-group>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="form" fxLayout="column">
|
||||
<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex="40">
|
||||
<input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
|
||||
#dateElement (focus)="dateElement.select()">
|
||||
<input
|
||||
matInput
|
||||
[matDatepicker]="date"
|
||||
placeholder="Date"
|
||||
formControlName="date"
|
||||
autocomplete="off"
|
||||
#dateElement
|
||||
(focus)="dateElement.select()"
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
</mat-form-field>
|
||||
@ -29,57 +41,85 @@
|
||||
<mat-form-field fxFlex="20">
|
||||
<mat-label>Amount</mat-label>
|
||||
<span matPrefix>₹ </span>
|
||||
<input type="text" matInput formControlName="amount">
|
||||
<input type="text" matInput formControlName="amount" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div formGroupName="addRow" fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px" fxLayoutGap.lt-md="0px">
|
||||
<div
|
||||
formGroupName="addRow"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="space-around start"
|
||||
fxLayout.lt-md="column"
|
||||
fxLayoutGap="20px"
|
||||
fxLayoutGap.lt-md="0px"
|
||||
>
|
||||
<mat-form-field fxFlex="55">
|
||||
<input type="text" matInput placeholder="Product" #batchElement [matAutocomplete]="autoB"
|
||||
formControlName="batch" autocomplete="off">
|
||||
<mat-autocomplete #autoB="matAutocomplete" autoActiveFirstOption [displayWith]="displayBatchName"
|
||||
(optionSelected)="batchSelected($event)">
|
||||
<mat-option *ngFor="let batch of batches | async" [value]="batch">{{batch.name}}</mat-option>
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="Product"
|
||||
#batchElement
|
||||
[matAutocomplete]="autoB"
|
||||
formControlName="batch"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#autoB="matAutocomplete"
|
||||
autoActiveFirstOption
|
||||
[displayWith]="displayBatchName"
|
||||
(optionSelected)="batchSelected($event)"
|
||||
>
|
||||
<mat-option *ngFor="let batch of batches | async" [value]="batch">{{
|
||||
batch.name
|
||||
}}</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25">
|
||||
<mat-label>Quantity</mat-label>
|
||||
<input type="text" matInput placeholder="Quantity" formControlName="quantity" autocomplete="off">
|
||||
<input
|
||||
type="text"
|
||||
matInput
|
||||
placeholder="Quantity"
|
||||
formControlName="quantity"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-raised-button color="primary" (click)="addRow()" fxFlex="20">Add</button>
|
||||
</div>
|
||||
<mat-table #table [dataSource]="dataSource" matSort aria-label="Elements">
|
||||
|
||||
<!-- Product Column -->
|
||||
<ng-container matColumnDef="product">
|
||||
<mat-header-cell *matHeaderCellDef>Product</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{row.product.name}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.product.name }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Batch Column -->
|
||||
<ng-container matColumnDef="batch">
|
||||
<mat-header-cell *matHeaderCellDef>Batch</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">{{row.batch.name}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ row.batch.name }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Quantity Column -->
|
||||
<ng-container matColumnDef="quantity">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Quantity</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.quantity | number:'1.2-2'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{
|
||||
row.quantity | number: '1.2-2'
|
||||
}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Rate Column -->
|
||||
<ng-container matColumnDef="rate">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Rate</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.rate | currency:'INR'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.rate | currency: 'INR' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Amount Column -->
|
||||
<ng-container matColumnDef="amount">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.amount | currency:'INR'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{
|
||||
row.amount | currency: 'INR'
|
||||
}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Action Column -->
|
||||
@ -96,51 +136,62 @@
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
</mat-table>
|
||||
<mat-form-field>
|
||||
<mat-label>Narration</mat-label>
|
||||
<textarea matInput matTextareaAutosize matAutosizeMinRows="5" placeholder="Narration"
|
||||
formControlName="narration"></textarea>
|
||||
<textarea
|
||||
matInput
|
||||
matTextareaAutosize
|
||||
matAutosizeMinRows="5"
|
||||
placeholder="Narration"
|
||||
formControlName="narration"
|
||||
></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="primary" (click)="save()" [disabled]="!canSave()">
|
||||
{{(voucher.id) ? 'Update' : 'Save'}}
|
||||
{{ voucher.id ? 'Update' : 'Save' }}
|
||||
</button>
|
||||
<button mat-raised-button color="warn" (click)="newVoucher()" *ngIf="voucher.id">
|
||||
New Entry
|
||||
</button>
|
||||
<button mat-raised-button color="warn" (click)="confirmDelete()" *ngIf="voucher.id" [disabled]="!canSave()">
|
||||
<button
|
||||
mat-raised-button
|
||||
color="warn"
|
||||
(click)="confirmDelete()"
|
||||
*ngIf="voucher.id"
|
||||
[disabled]="!canSave()"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
<mat-card-subtitle *ngIf="voucher.id">
|
||||
Created on <strong>{{voucher.creationDate | localTime}}</strong> and
|
||||
Last Edited on <strong>{{voucher.lastEditDate | localTime}}</strong>
|
||||
by <strong>{{voucher.user.name}}</strong>. {{(voucher.poster) ? 'Posted by ' + voucher.poster : ''}}
|
||||
Created on <strong>{{ voucher.creationDate | localTime }}</strong> and Last Edited on
|
||||
<strong>{{ voucher.lastEditDate | localTime }}</strong> by
|
||||
<strong>{{ voucher.user.name }}</strong
|
||||
>. {{ voucher.poster ? 'Posted by ' + voucher.poster : '' }}
|
||||
</mat-card-subtitle>
|
||||
<mat-card-title>Other issues for the day</mat-card-title>
|
||||
<mat-card-footer>
|
||||
<mat-table #table [dataSource]="gridDataSource" matSort aria-label="Elements">
|
||||
|
||||
<!-- Source Column -->
|
||||
<ng-container matColumnDef="source">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Source</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.source}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.source }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Destination Column -->
|
||||
<ng-container matColumnDef="destination">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Destination</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.destination}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.destination }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Amount Column -->
|
||||
<ng-container matColumnDef="gridAmount">
|
||||
<mat-header-cell *matHeaderCellDef class="right">Amount</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{row.amount | currency:'INR'}}</mat-cell>
|
||||
<mat-cell *matCellDef="let row" class="right">{{ row.amount | currency: 'INR' }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- Load Column -->
|
||||
@ -154,7 +205,7 @@
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="gridColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: gridColumns;"></mat-row>
|
||||
<mat-row *matRowDef="let row; columns: gridColumns"></mat-row>
|
||||
</mat-table>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {IssueComponent} from './issue.component';
|
||||
import { IssueComponent } from './issue.component';
|
||||
|
||||
describe('IssueComponent', () => {
|
||||
let component: IssueComponent;
|
||||
@ -8,9 +8,8 @@ describe('IssueComponent', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IssueComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
declarations: [IssueComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
|
||||
import {FormBuilder, FormGroup} from '@angular/forms';
|
||||
import { AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {BehaviorSubject, Observable, of as observableOf} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
||||
import {IssueDataSource} from './issue-datasource';
|
||||
import {VoucherService} from '../core/voucher.service';
|
||||
import {Batch, Inventory, Voucher} from '../core/voucher';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
|
||||
import { IssueDataSource } from './issue-datasource';
|
||||
import { VoucherService } from '../core/voucher.service';
|
||||
import { Batch, Inventory, Voucher } from '../core/voucher';
|
||||
import * as moment from 'moment';
|
||||
import {AuthService} from '../auth/auth.service';
|
||||
import {ConfirmDialogComponent} from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
import {ToasterService} from '../core/toaster.service';
|
||||
import {IssueDialogComponent} from './issue-dialog.component';
|
||||
import {BatchService} from '../core/batch.service';
|
||||
import {IssueGridService} from './issue-grid.service';
|
||||
import {CostCentre} from '../core/cost-centre';
|
||||
import {IssueGridDataSource} from './issue-grid-datasource';
|
||||
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||
import { AuthService } from '../auth/auth.service';
|
||||
import { ConfirmDialogComponent } from '../shared/confirm-dialog/confirm-dialog.component';
|
||||
import { ToasterService } from '../core/toaster.service';
|
||||
import { IssueDialogComponent } from './issue-dialog.component';
|
||||
import { BatchService } from '../core/batch.service';
|
||||
import { IssueGridService } from './issue-grid.service';
|
||||
import { CostCentre } from '../core/cost-centre';
|
||||
import { IssueGridDataSource } from './issue-grid-datasource';
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys';
|
||||
|
||||
@Component({
|
||||
selector: 'app-issue',
|
||||
templateUrl: './issue.component.html',
|
||||
styleUrls: ['./issue.component.css']
|
||||
styleUrls: ['./issue.component.css'],
|
||||
})
|
||||
export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('batchElement', { static: true }) batchElement: ElementRef;
|
||||
@ -51,7 +51,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private auth: AuthService,
|
||||
private ser: VoucherService,
|
||||
private batchSer: BatchService,
|
||||
private issueGridSer: IssueGridService
|
||||
private issueGridSer: IssueGridService,
|
||||
) {
|
||||
this.createForm();
|
||||
this.listenToBatchAutocompleteChange();
|
||||
@ -60,23 +60,34 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
ngOnInit() {
|
||||
this.gridDataSource = new IssueGridDataSource(this.gridObservable);
|
||||
this.route.data
|
||||
.subscribe((data: { voucher: Voucher, costCentres: CostCentre[] }) => {
|
||||
this.costCentres = data.costCentres;
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
|
||||
setTimeout(() => {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||
this.route.data.subscribe((data: { voucher: Voucher; costCentres: CostCentre[] }) => {
|
||||
this.costCentres = data.costCentres;
|
||||
this.loadVoucher(data.voucher);
|
||||
});
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'f2',
|
||||
(event: KeyboardEvent): boolean => {
|
||||
setTimeout(() => {
|
||||
this.dateElement.nativeElement.focus();
|
||||
}, 0);
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
this.hotkeys.add(
|
||||
new Hotkey(
|
||||
'ctrl+s',
|
||||
(event: KeyboardEvent): boolean => {
|
||||
if (this.canSave()) {
|
||||
this.save();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
},
|
||||
['INPUT', 'SELECT', 'TEXTAREA'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
@ -96,9 +107,9 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)),
|
||||
addRow: {
|
||||
batch: '',
|
||||
quantity: ''
|
||||
quantity: '',
|
||||
},
|
||||
narration: this.voucher.narration
|
||||
narration: this.voucher.narration,
|
||||
});
|
||||
this.dataSource = new IssueDataSource(this.inventoryObservable);
|
||||
this.updateView();
|
||||
@ -112,12 +123,14 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
addRow() {
|
||||
const formValue = this.form.get('addRow').value;
|
||||
const quantity = +(formValue.quantity);
|
||||
const quantity = +formValue.quantity;
|
||||
const isConsumption = this.form.value.source === '7b845f95-dfef-fa4a-897c-f0baf15284a3';
|
||||
if (this.batch === null || quantity <= 0) {
|
||||
return;
|
||||
}
|
||||
const oldFiltered = this.voucher.inventories.filter((x) => x.product.id === this.batch.product.id);
|
||||
const oldFiltered = this.voucher.inventories.filter(
|
||||
(x) => x.product.id === this.batch.product.id,
|
||||
);
|
||||
const old = oldFiltered.length ? oldFiltered[0] : null;
|
||||
if (oldFiltered.length) {
|
||||
if (old.batch.id !== this.batch.id) {
|
||||
@ -142,7 +155,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
discount: this.batch.discount,
|
||||
amount: quantity * this.batch.rate * (1 + this.batch.tax) * (1 - this.batch.discount),
|
||||
product: this.batch.product,
|
||||
batch: this.batch
|
||||
batch: this.batch,
|
||||
});
|
||||
}
|
||||
this.resetAddRow();
|
||||
@ -152,7 +165,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
resetAddRow() {
|
||||
this.form.get('addRow').reset({
|
||||
batch: null,
|
||||
quantity: ''
|
||||
quantity: '',
|
||||
});
|
||||
this.batch = null;
|
||||
setTimeout(() => {
|
||||
@ -162,14 +175,19 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
updateView() {
|
||||
this.inventoryObservable.next(this.voucher.inventories);
|
||||
const amount = Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0));
|
||||
const amount = Math.abs(
|
||||
this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0),
|
||||
);
|
||||
this.form.get('amount').setValue(amount);
|
||||
}
|
||||
|
||||
editRow(row: Inventory) {
|
||||
const dialogRef = this.dialog.open(IssueDialogComponent, {
|
||||
width: '750px',
|
||||
data: {inventory: Object.assign({}, row), date: moment(this.form.value.date).format('DD-MMM-YYYY')}
|
||||
data: {
|
||||
inventory: Object.assign({}, row),
|
||||
date: moment(this.form.value.date).format('DD-MMM-YYYY'),
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result: boolean | Inventory) => {
|
||||
@ -177,7 +195,10 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
const j = result as Inventory;
|
||||
if (j.product.id !== row.product.id && this.voucher.inventories.filter((x) => x.product.id === j.product.id).length) {
|
||||
if (
|
||||
j.product.id !== row.product.id &&
|
||||
this.voucher.inventories.filter((x) => x.product.id === j.product.id).length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
Object.assign(row, j);
|
||||
@ -195,12 +216,12 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
date: '',
|
||||
source: '',
|
||||
destination: '',
|
||||
amount: {value: '', disabled: true},
|
||||
amount: { value: '', disabled: true },
|
||||
addRow: this.fb.group({
|
||||
batch: '',
|
||||
quantity: ''
|
||||
quantity: '',
|
||||
}),
|
||||
narration: ''
|
||||
narration: '',
|
||||
});
|
||||
}
|
||||
|
||||
@ -210,26 +231,28 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
} else if (this.voucher.posted && this.auth.user.perms.indexOf('edit-posted-vouchers') !== -1) {
|
||||
return true;
|
||||
} else {
|
||||
return this.voucher.user.id === this.auth.user.id || this.auth.user.perms.indexOf("edit-other-user's-vouchers") !== -1;
|
||||
return (
|
||||
this.voucher.user.id === this.auth.user.id ||
|
||||
this.auth.user.perms.indexOf("edit-other-user's-vouchers") !== -1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
const voucher: Voucher = this.getVoucher();
|
||||
this.ser.saveOrUpdate(voucher)
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
this.ser.saveOrUpdate(voucher).subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
if (voucher.id === result.id) {
|
||||
this.loadVoucher(result);
|
||||
} else {
|
||||
this.router.navigate(['/issue', result.id]);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
}
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
newVoucher() {
|
||||
@ -246,22 +269,21 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
delete() {
|
||||
this.ser.delete(this.voucher.id)
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigate(['/issue'], {replaceUrl: true});
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
}
|
||||
);
|
||||
this.ser.delete(this.voucher.id).subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigate(['/issue'], { replaceUrl: true });
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
confirmDelete(): void {
|
||||
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||
width: '250px',
|
||||
data: {title: 'Delete Voucher?', content: 'Are you sure? This cannot be undone.'}
|
||||
data: { title: 'Delete Voucher?', content: 'Are you sure? This cannot be undone.' },
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result: boolean) => {
|
||||
@ -273,33 +295,28 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
listenToBatchAutocompleteChange(): void {
|
||||
const control = this.form.get('addRow').get('batch');
|
||||
this.batches = control.valueChanges
|
||||
.pipe(
|
||||
startWith(null),
|
||||
map(x => (x !== null && x.length >= 1) ? x : null),
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
switchMap(
|
||||
x => (x === null) ? observableOf([]) : this.batchSer.autocomplete(
|
||||
moment(this.form.value.date).format('DD-MMM-YYYY'), x
|
||||
)
|
||||
)
|
||||
);
|
||||
this.batches = control.valueChanges.pipe(
|
||||
startWith(null),
|
||||
map((x) => (x !== null && x.length >= 1 ? x : null)),
|
||||
debounceTime(150),
|
||||
distinctUntilChanged(),
|
||||
switchMap((x) =>
|
||||
x === null
|
||||
? observableOf([])
|
||||
: this.batchSer.autocomplete(moment(this.form.value.date).format('DD-MMM-YYYY'), x),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
listenToDateChange(): void {
|
||||
this.form.get('date').valueChanges
|
||||
.pipe(
|
||||
map(x => moment(x).format('DD-MMM-YYYY'))
|
||||
)
|
||||
.subscribe(x => this.showGrid(x));
|
||||
this.form
|
||||
.get('date')
|
||||
.valueChanges.pipe(map((x) => moment(x).format('DD-MMM-YYYY')))
|
||||
.subscribe((x) => this.showGrid(x));
|
||||
}
|
||||
|
||||
showGrid(date: string) {
|
||||
this.issueGridSer.issueGrid(date)
|
||||
.subscribe(
|
||||
x => this.gridObservable.next(x)
|
||||
);
|
||||
this.issueGridSer.issueGrid(date).subscribe((x) => this.gridObservable.next(x));
|
||||
}
|
||||
|
||||
displayBatchName(batch?: Batch): string | undefined {
|
||||
@ -313,5 +330,4 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
goToVoucher(id: string) {
|
||||
this.router.navigate(['/issue', id]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {IssueModule} from './issue.module';
|
||||
import { IssueModule } from './issue.module';
|
||||
|
||||
describe('IssueModule', () => {
|
||||
let issueModule: IssueModule;
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule } from '@angular/material/core';
|
||||
import {
|
||||
DateAdapter,
|
||||
MAT_DATE_FORMATS,
|
||||
MAT_DATE_LOCALE,
|
||||
MatNativeDateModule,
|
||||
} from '@angular/material/core';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
@ -15,16 +20,16 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import {SharedModule} from '../shared/shared.module';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {CdkTableModule} from '@angular/cdk/table';
|
||||
import {IssueRoutingModule} from './issue-routing.module';
|
||||
import {IssueComponent} from './issue.component';
|
||||
import {MomentDateAdapter} from '@angular/material-moment-adapter';
|
||||
import {A11yModule} from '@angular/cdk/a11y';
|
||||
import {IssueDialogComponent} from './issue-dialog.component';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {HotkeyModule} from "angular2-hotkeys";
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { CdkTableModule } from '@angular/cdk/table';
|
||||
import { IssueRoutingModule } from './issue-routing.module';
|
||||
import { IssueComponent } from './issue.component';
|
||||
import { MomentDateAdapter } from '@angular/material-moment-adapter';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import { IssueDialogComponent } from './issue-dialog.component';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { HotkeyModule } from 'angular2-hotkeys';
|
||||
|
||||
export const MY_FORMATS = {
|
||||
parse: {
|
||||
@ -62,16 +67,12 @@ export const MY_FORMATS = {
|
||||
MatTableModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
IssueRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
IssueComponent,
|
||||
IssueDialogComponent
|
||||
IssueRoutingModule,
|
||||
],
|
||||
declarations: [IssueComponent, IssueDialogComponent],
|
||||
providers: [
|
||||
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
|
||||
{provide: MAT_DATE_FORMATS, useValue: MY_FORMATS},
|
||||
]
|
||||
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
|
||||
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
|
||||
],
|
||||
})
|
||||
export class IssueModule {
|
||||
}
|
||||
export class IssueModule {}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import {inject, TestBed} from '@angular/core/testing';
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {VoucherService} from './issue.service';
|
||||
import { VoucherService } from './issue.service';
|
||||
|
||||
describe('IssueService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [VoucherService]
|
||||
providers: [VoucherService],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user