From 7ba346e60a0aa52b0ab9907516e7dc78e0adc902 Mon Sep 17 00:00:00 2001 From: Akash Shah Date: Wed, 17 Jul 2019 02:29:17 -0400 Subject: [PATCH] qty renderer and formatter added and implemented: bug to fix: weird fraction issue Added functoinality to delete detail buttonn (both SO and Inv) --- .../in-det-qty-editor.component.spec.ts | 25 +++++++ .../in-det-qty-editor.component.ts | 54 +++++++++++++++ .../numeric-editor.component.ts | 3 +- .../so-qty-editor.component.spec.ts | 25 +++++++ .../so-qty-editor/so-qty-editor.component.ts | 67 +++++++++++++++++++ .../so-qty-formatter.component.spec.ts | 25 +++++++ .../so-qty-formatter.component.ts | 24 +++++++ AstuteClient2/src/app/app.module.ts | 13 +++- .../src/app/invoice/invoice.component.html | 3 +- .../src/app/invoice/invoice.component.ts | 41 ++++++++++-- .../sales-order/sales-order.component.html | 3 +- .../app/sales-order/sales-order.component.ts | 39 +++++++++-- 12 files changed, 306 insertions(+), 16 deletions(-) create mode 100644 AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.spec.ts create mode 100644 AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.ts create mode 100644 AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.spec.ts create mode 100644 AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.ts create mode 100644 AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.spec.ts create mode 100644 AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.ts diff --git a/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.spec.ts b/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.spec.ts new file mode 100644 index 0000000..1d679b5 --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { InDetQtyEditorComponent } from './in-det-qty-editor.component'; + +describe('InDetQtyEditorComponent', () => { + let component: InDetQtyEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ InDetQtyEditorComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(InDetQtyEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.ts b/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.ts new file mode 100644 index 0000000..4432bbc --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/in-det-qty-editor/in-det-qty-editor.component.ts @@ -0,0 +1,54 @@ +import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {ToastManagerService} from '../../services/toast-manager/toast-service.service'; + +@Component({ + selector: 'app-in-det-qty-editor', + template: ` + + ` +}) +export class InDetQtyEditorComponent implements AfterViewInit { + @ViewChild('i', {'static': false}) numberInput; + params; + remainingQty: number; + + constructor(protected toastService: ToastManagerService) { } + + ngAfterViewInit() { + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } + + agInit(params: any): void { + this.params = params; + this.remainingQty = params.remainingQty + params.value; + } + + getValue() { + return this.numberInput.nativeElement.value; + } + + onKeyDown(event) { + if (event.keyCode === 9 || event.keyCode === 13) { + if (!this.numberInput.nativeElement.value) { + event.stopPropagation(); + this.notif('Value should not be empty'); + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } else if (this.numberInput.nativeElement.value < 0 || this.numberInput.nativeElement.value > this.remainingQty) { + event.stopPropagation(); + this.notif('Value should between 0 and ' + this.remainingQty); + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } + } + } + + // ** toast notification method + notif(text: string) { + this.toastService.show(text, {classname: 'bg-warning'}); + } +} diff --git a/AstuteClient2/src/app/ag-grid-components/numeric-editor/numeric-editor.component.ts b/AstuteClient2/src/app/ag-grid-components/numeric-editor/numeric-editor.component.ts index b9aa550..9384a13 100644 --- a/AstuteClient2/src/app/ag-grid-components/numeric-editor/numeric-editor.component.ts +++ b/AstuteClient2/src/app/ag-grid-components/numeric-editor/numeric-editor.component.ts @@ -47,5 +47,4 @@ export class NumericEditorComponent implements AfterViewInit { notif(text: string) { this.toastService.show(text, {classname: 'bg-warning'}); } -} - +} \ No newline at end of file diff --git a/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.spec.ts b/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.spec.ts new file mode 100644 index 0000000..af63911 --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SoQtyEditorComponent } from './so-qty-editor.component'; + +describe('SoQtyEditorComponent', () => { + let component: SoQtyEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SoQtyEditorComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SoQtyEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.ts b/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.ts new file mode 100644 index 0000000..b4d74c5 --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/so-qty-editor/so-qty-editor.component.ts @@ -0,0 +1,67 @@ +import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {ToastManagerService} from '../../services/toast-manager/toast-service.service'; + +@Component({ + selector: 'app-so-qty-editor', + template: ` + + + ` +}) +export class SoQtyEditorComponent implements AfterViewInit { + @ViewChild('i', {'static': false}) numberInput; + params; + feeTypeId: number; + + constructor(protected toastService: ToastManagerService) { } + + ngAfterViewInit() { + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } + + agInit(params: any): void { + this.params = params; + this.feeTypeId = params.feeTypeId; + } + + getValue() { + return this.numberInput.nativeElement.value; + } + + onKeyDown(event) { + if (event.keyCode === 9 || event.keyCode === 13) { + if (!this.numberInput.nativeElement.value) { + event.stopPropagation(); + this.notif('Value should not be empty'); + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } else if (this.feeTypeId === 1) { + if (this.numberInput.nativeElement.value < 0 || this.numberInput.nativeElement.value > 1) { + event.stopPropagation(); + this.notif('Value should be between 0 and 1'); + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } + } else if (this.feeTypeId === 2) { + if (this.numberInput.nativeElement.value < 0) { + event.stopPropagation(); + this.notif('Value should less than 0'); + setTimeout(() => { + this.numberInput.nativeElement.focus(); + }); + } + } + } + } + + // ** toast notification method + notif(text: string) { + this.toastService.show(text, {classname: 'bg-warning'}); + } +} diff --git a/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.spec.ts b/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.spec.ts new file mode 100644 index 0000000..102c726 --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SoQtyFormatterComponent } from './so-qty-formatter.component'; + +describe('SoQtyFormatterComponent', () => { + let component: SoQtyFormatterComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SoQtyFormatterComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SoQtyFormatterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.ts b/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.ts new file mode 100644 index 0000000..9066227 --- /dev/null +++ b/AstuteClient2/src/app/ag-grid-components/so-qty-formatter/so-qty-formatter.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-so-qty-formatter', + template: ` +
+ {{(params.value * 100).toFixed(0)}} + % +
+
+ {{params.value}} + hours +
+ ` +}) +export class SoQtyFormatterComponent { + params: any; + feeTypeId: number; + + agInit(params: any): void { + this.params = params; + this.feeTypeId = params.feeTypeId; + } +} \ No newline at end of file diff --git a/AstuteClient2/src/app/app.module.ts b/AstuteClient2/src/app/app.module.ts index 2480b58..d1c8eb7 100644 --- a/AstuteClient2/src/app/app.module.ts +++ b/AstuteClient2/src/app/app.module.ts @@ -28,6 +28,9 @@ import { PhoneFormatterComponent } from './ag-grid-components/phone-formatter/ph import { PhoneEditorComponent } from './ag-grid-components/phone-editor/phone-editor.component'; import { EmptyErrorEditorComponent } from './ag-grid-components/empty-error-editor/empty-error-editor.component'; import { NumericEditorComponent } from './ag-grid-components/numeric-editor/numeric-editor.component'; +import { SoQtyEditorComponent } from './ag-grid-components/so-qty-editor/so-qty-editor.component'; +import { InDetQtyEditorComponent } from './ag-grid-components/in-det-qty-editor/in-det-qty-editor.component'; +import { SoQtyFormatterComponent } from './ag-grid-components/so-qty-formatter/so-qty-formatter.component'; // import { ServiceTypeComponent } from './service-type/service-type.component'; @NgModule({ @@ -49,7 +52,10 @@ import { NumericEditorComponent } from './ag-grid-components/numeric-editor/nume PhoneFormatterComponent, PhoneEditorComponent, EmptyErrorEditorComponent, - NumericEditorComponent// , + NumericEditorComponent, + SoQtyEditorComponent, + InDetQtyEditorComponent, + SoQtyFormatterComponent// , // ServiceTypeComponent ], imports: [ @@ -59,7 +65,10 @@ import { NumericEditorComponent } from './ag-grid-components/numeric-editor/nume PhoneFormatterComponent, PhoneEditorComponent, EmptyErrorEditorComponent, - NumericEditorComponent + NumericEditorComponent, + SoQtyEditorComponent, + InDetQtyEditorComponent, + SoQtyFormatterComponent ]), NgbModule, HttpClientModule, diff --git a/AstuteClient2/src/app/invoice/invoice.component.html b/AstuteClient2/src/app/invoice/invoice.component.html index ef76648..55de2d5 100644 --- a/AstuteClient2/src/app/invoice/invoice.component.html +++ b/AstuteClient2/src/app/invoice/invoice.component.html @@ -704,7 +704,8 @@ Add diff --git a/AstuteClient2/src/app/invoice/invoice.component.ts b/AstuteClient2/src/app/invoice/invoice.component.ts index 7af3fde..20fc47b 100644 --- a/AstuteClient2/src/app/invoice/invoice.component.ts +++ b/AstuteClient2/src/app/invoice/invoice.component.ts @@ -1,9 +1,10 @@ -import {Component, OnInit, ViewChild} from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {AstuteClientService} from '../services/astute-client-service'; -import {formatCurrency} from '@angular/common'; import {PrintInvoiceService} from '../services/print-invoice.service'; import {ToastManagerService} from '../services/toast-manager/toast-service.service'; import {NumberFormatterComponent} from '../ag-grid-components/number-formatter/number-formatter.component'; +import {SoQtyFormatterComponent} from '../ag-grid-components/so-qty-formatter/so-qty-formatter.component'; +import {InDetQtyEditorComponent} from '../ag-grid-components/in-det-qty-editor/in-det-qty-editor.component'; declare var $: any; @@ -64,7 +65,9 @@ export class InvoiceComponent implements OnInit { } }; frameworkComponents = { - numberFormatterComponent: NumberFormatterComponent + numberFormatterComponent: NumberFormatterComponent, + soQtyFormatterComponent: SoQtyFormatterComponent, + inDetQtyEditorComponent: InDetQtyEditorComponent }; detailColumnDefs = [ {headerName: '#', field: 'lineItemNum'}, @@ -76,10 +79,14 @@ export class InvoiceComponent implements OnInit { cellEditor: 'agSelectCellEditor', cellEditorParams: {values: this.rateNames}}, {headerName: 'Service Type', field: 'serviceTypeName'}, {headerName: 'Qty or Hours ✎*', field: 'qty', - editable: (_ => (this.chosenInv && this.chosenInv.invoiceStatus === 1))}, - {headerName: 'Remaining Qty', field: 'remainingQty'}, + editable: (_ => (this.chosenInv && this.chosenInv.invoiceStatus === 1)), + cellEditor: 'inDetQtyEditorComponent', cellEditorParams: (node => ({remainingQty: node.data.draftRemainingQty})), + cellRenderer: 'soQtyFormatterComponent', cellRendererParams: (node => ({feeTypeId: node.data.feeTypeId}))}, + {headerName: 'Remaining Qty', field: 'remainingQty', + cellRenderer: 'soQtyFormatterComponent', cellRendererParams: (node => ({feeTypeId: node.data.feeTypeId}))}, {headerName: 'Fee *', field: 'fee', - editable: (node => (node.data.poLineItemNum === -1 && this.chosenInv && this.chosenInv.invoiceStatus === 1)), cellRenderer: 'numberFormatterComponent'} + editable: (node => (node.data.poLineItemNum === -1 && this.chosenInv && this.chosenInv.invoiceStatus === 1)), + cellRenderer: 'numberFormatterComponent'} ]; @@ -478,6 +485,7 @@ export class InvoiceComponent implements OnInit { if (data) { console.log('Invoice, ' + invoiceNum + ' successfully deleted'); this.refreshData(); + this.refreshPOs(); } else { this.notif ('Error in deleting; Invoice, ' + invoiceNum + ' has not been deleted'); } @@ -564,6 +572,7 @@ export class InvoiceComponent implements OnInit { this.astuteClientService.voidInvoice(invoiceNumber).then((data) => { if (data) { this.refreshData(); + this.refreshPOs(); } else { this.notif('void invoice failed.'); } @@ -574,6 +583,7 @@ export class InvoiceComponent implements OnInit { this.astuteClientService.submitInvoice(invoiceNumber).then((data) => { if (data) { this.refreshData(); + this.refreshPOs(); } else { this.notif('submit invoice failed.'); } @@ -628,6 +638,25 @@ export class InvoiceComponent implements OnInit { this.notif('Creating Invoice details failed: ' + reason); }); } + deleteInvDetail() { + const selectedNodes = this.detailGridApi.getSelectedNodes(); + if (selectedNodes.length > 0) { + if (confirm('Are you sure?')) { + const selec = selectedNodes.map(node => node.data)[0]; + this.astuteClientService.deleteInvoiceDetail(selec.invoiceNum, selec.lineItemNum).then((data) => { + if (data) { + this.refreshDetailsOfSelected(); + } else { + this.notif('Invoice Detail Deletion Failed!'); + } + }, (reason) => { + this.notif('Delete Invoice Detail failed: ' + reason); + }); + } + } else { + this.notif('Choose a Invoice Detail first!'); + } + } // addInvoiceDetail(details) { // if (details.length) { diff --git a/AstuteClient2/src/app/sales-order/sales-order.component.html b/AstuteClient2/src/app/sales-order/sales-order.component.html index 3cb0dde..dd495f3 100644 --- a/AstuteClient2/src/app/sales-order/sales-order.component.html +++ b/AstuteClient2/src/app/sales-order/sales-order.component.html @@ -438,7 +438,8 @@ Add diff --git a/AstuteClient2/src/app/sales-order/sales-order.component.ts b/AstuteClient2/src/app/sales-order/sales-order.component.ts index a27326d..fb91f62 100644 --- a/AstuteClient2/src/app/sales-order/sales-order.component.ts +++ b/AstuteClient2/src/app/sales-order/sales-order.component.ts @@ -4,6 +4,8 @@ import {formatCurrency, formatNumber} from '@angular/common'; import {ToastManagerService} from '../services/toast-manager/toast-service.service'; import {NumberFormatterComponent} from '../ag-grid-components/number-formatter/number-formatter.component'; import {EmptyErrorEditorComponent} from "../ag-grid-components/empty-error-editor/empty-error-editor.component"; +import {SoQtyEditorComponent} from "../ag-grid-components/so-qty-editor/so-qty-editor.component"; +import {SoQtyFormatterComponent} from "../ag-grid-components/so-qty-formatter/so-qty-formatter.component"; @Component({ selector: 'app-sales-order', @@ -56,7 +58,9 @@ export class SalesOrderComponent implements OnInit { frameworkComponents = { emptyErrorEditorComponent: EmptyErrorEditorComponent, - numberFormatterComponent: NumberFormatterComponent + numberFormatterComponent: NumberFormatterComponent, + soQtyEditorComponent: SoQtyEditorComponent, + soQtyFormatterComponent: SoQtyFormatterComponent }; selected = null; // the selected SO row @@ -71,7 +75,10 @@ export class SalesOrderComponent implements OnInit { cellEditor: 'agSelectCellEditor', cellEditorParams: {values: this.rateNames}}, {headerName: 'Service Type ✎', field: 'serviceTypeName', editable: (_ => (this.selected && !this.selected.isFinal)), cellEditor: 'agSelectCellEditor', cellEditorParams: {values: this.serviceNames}}, - {headerName: 'Qty or Hours ✎', field: 'qty', editable: (_ => (this.selected && !this.selected.isFinal))}, + {headerName: 'Qty or Hours *', field: 'qty', + editable: (node => (node.data.feeTypeId === 2 && this.selected && !this.selected.isFinal)), + cellEditor: 'soQtyEditorComponent', cellEditorParams: (node => ({feeTypeId: node.data.feeTypeId})), + cellRenderer: 'soQtyFormatterComponent', cellRendererParams: (node => ({feeTypeId: node.data.feeTypeId}))}, {headerName: 'Rate ($) ✎', field: 'fee', editable: (_ => (this.selected && !this.selected.isFinal)), cellRenderer: 'numberFormatterComponent'} ]; @@ -174,10 +181,11 @@ export class SalesOrderComponent implements OnInit { this.astuteClientService.updatePODetail(eventData.poNum, eventData.lineItemNo, eventData).then((data) => { if (!data) { this.notif('SO Detail updating failed, check input fields'); - this.refreshDetailsOfSelected(); } else { this.updateContractAmt(); } + this.refreshDetailsOfSelected(); + // this.refreshData(); }, (reason) => { this.notif('Update SO Detail failed: ' + reason); }); @@ -290,7 +298,25 @@ export class SalesOrderComponent implements OnInit { this.notif('Creating SO detailed failed: ' + reason); }); } - + deletePODetail() { + const selectedNodes = this.detailGridApi.getSelectedNodes(); + if (selectedNodes.length > 0) { + if (confirm('Are you sure?')) { + const selec = selectedNodes.map(node => node.data)[0]; + this.astuteClientService.deletePODetail(selec.poNum, selec.lineItemNo).then((data) => { + if (data) { + this.refreshDetailsOfSelected(); + } else { + this.notif('SO Detail Deletion Failed'); + } + }, (reason) => { + this.notif('Delete SO failed: ' + reason); + }); + } + } else { + this.notif('Choose a SO first!'); + } + } // open and closing modal-form components open(ref) { @@ -329,6 +355,8 @@ export class SalesOrderComponent implements OnInit { // }, (reason) => { // this.notif('Get SO\'s Failed: ' + reason); // }); + + const selectedRow = (this.gridApi ? this.gridApi.getSelectedRows()[0] : null); this.rowData = this.astuteClientService.getPOs().then((data) => { if (data) { // this.pos = data; @@ -345,6 +373,9 @@ export class SalesOrderComponent implements OnInit { }, (reason) => { this.notif('Get SO\'s Failed: ' + reason); }); + if (selectedRow) { + // this.gridApi.setSelectedRow(selectedRow); + } } refreshDetailsOfSelected() { this.setSelectedRow(null);