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<InDetQtyEditorComponent>;
+
+  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: `
+      <input #i type="number" min="0" [max]="remainingQty" class="w-100" [value]="params.value" (keydown)="onKeyDown($event)"/>
+    `
+})
+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<SoQtyEditorComponent>;
+
+  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: `
+      <input #i *ngIf="feeTypeId === 1" type="number" min="0" [max]="1" step="0.1"
+             class="w-100" [value]="params.value" (keydown)="onKeyDown($event)"/>
+      <input #i *ngIf="feeTypeId === 2" type="number" min="0" step="1"
+             class="w-100" [value]="params.value" (keydown)="onKeyDown($event)"/>
+    `
+})
+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<SoQtyFormatterComponent>;
+
+  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: `
+        <div *ngIf="feeTypeId === 1">
+            <span *ngIf="feeTypeId === 1">{{(params.value * 100).toFixed(0)}} </span>
+            <span style="color: darkgrey">%</span>
+        </div>
+        <div *ngIf="feeTypeId === 2">
+            <span *ngIf="feeTypeId === 2">{{params.value}} </span>
+            <span style="color: darkgrey">hours</span>
+        </div>
+    `
+})
+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
                                 </button>
                                 <button class="btn btn-danger w-50 input-group-sm" type="button"
-                                        [disabled]="true">
+                                        (click)="deleteInvDetail(); poDetailSelec.selectedIndex = 0"
+                                        [disabled]="(chosenInv ? chosenInv.invoiceStatus === 2 || chosenInv.invoiceStatus === 3: false)">
                                     Delete
                                 </button>
                             </div>
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
                 </button>
                 <button class="btn btn-danger w-50 input-group-sm" type="button"
-                        [disabled]="true">
+                        (click)="deletePODetail()"
+                        [disabled]="(selected ? selected.isFinal : false)">
                   Delete
                 </button>
               </div>
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);