mirror of
https://github.com/dyiop/astute.git
synced 2025-04-06 21:30:20 -04:00
- customer and sales order are updated with new workflow for details - invoice has yet to be updated to the new workflow - added a settings tab and put service types and logout on there - updated homepage and nav-bar accordingly
395 lines
13 KiB
TypeScript
395 lines
13 KiB
TypeScript
import {Component, OnInit, ViewChild} from '@angular/core';
|
|
import {AstuteClientService} from '../services/astute-client-service';
|
|
import {formatCurrency} from '@angular/common';
|
|
|
|
@Component({
|
|
selector: 'app-sales-order',
|
|
templateUrl: './sales-order.component.html',
|
|
styleUrls: ['./sales-order.component.css']
|
|
})
|
|
export class SalesOrderComponent implements OnInit {
|
|
// both of the grid api's
|
|
gridApi;
|
|
gridColumnApi;
|
|
detailGridApi;
|
|
detailColumnApi;
|
|
|
|
// one time fetch meta-data
|
|
customers;
|
|
serviceTypes;
|
|
serviceNames = [];
|
|
rateTypes = [];
|
|
rateNames = [];
|
|
|
|
// data for SO grid
|
|
rowData: any;
|
|
columnDefs = [
|
|
{headerName: 'Project Number', field: 'astuteProjectNumber', editable: true},
|
|
{headerName: 'SO Number', field: 'ponum'},
|
|
// {headerName: 'Customer ID', field: 'customerId'},
|
|
{headerName: 'Customer Name', field: 'customerName'},
|
|
{headerName: 'Contract Number', field: 'contractNum', editable: true},
|
|
{headerName: 'SO Title', field: 'title', editable: true},
|
|
{headerName: 'Contract Amount', field: 'contractAmtString'},
|
|
// {headerName: 'Contract Amount', field: 'contractAmt'},
|
|
{headerName: 'SO Date', field: 'podate', editable: true},
|
|
{headerName: '# of Invoice', field: 'invoiceSequence'},
|
|
{headerName: 'notes', field: 'notes', editable: true, cellEditor: 'agLargeTextCellEditor'}
|
|
// {headerName: 'oneInvInDraft', field: 'oneInvInDraft'}
|
|
];
|
|
selected = null; // the selected SO row
|
|
|
|
// data for SO detail grid
|
|
selectedPODetail;
|
|
detailColumnDefs = [
|
|
{headerName: '#', field: 'lineItemNo'},
|
|
{headerName: 'Description', field: 'serviceDesc', editable: true},
|
|
{headerName: 'Rate Type', field: 'rateTypeName', editable: true,
|
|
cellEditor: 'agSelectCellEditor', cellEditorParams: {values: this.rateNames}},
|
|
{headerName: 'Service Type', field: 'serviceTypeName', editable: true,
|
|
cellEditor: 'agSelectCellEditor', cellEditorParams: {values: this.serviceNames}},
|
|
{headerName: 'Qty or Hours', field: 'qty', editable: true},
|
|
{headerName: 'Rate ($)', field: 'fee', editable: true}
|
|
];
|
|
contractAmount = 0; // used to show total amount
|
|
|
|
constructor(private astuteClientService: AstuteClientService) {
|
|
}
|
|
|
|
ngOnInit() {
|
|
this.astuteClientService.getServiceTypes().then((d) => {
|
|
if (d) {
|
|
this.serviceTypes = d;
|
|
this.serviceTypes.forEach((type) => {
|
|
this.serviceNames.push(type.serviceTypeDesc);
|
|
});
|
|
// console.log(this.serviceNames);
|
|
} else {
|
|
alert ('Get service types failed');
|
|
}
|
|
}, reason => {
|
|
alert('Get service type failed: ' + reason);
|
|
});
|
|
this.astuteClientService.getRateTypes().then((d) => {
|
|
if (d) {
|
|
this.rateTypes = d;
|
|
this.rateTypes.forEach((type) => {
|
|
this.rateNames.push(type.feeTypeDesc);
|
|
});
|
|
} else {
|
|
alert ('Get rate types failed');
|
|
}
|
|
}, reason => {
|
|
alert('Get rate type failed: ' + reason);
|
|
});
|
|
this.astuteClientService.getCustomers().then((customers) => {
|
|
if (customers) {
|
|
this.customers = customers;
|
|
this.refreshData();
|
|
} else {
|
|
alert('Get Customers Failed!');
|
|
}
|
|
}, (reason) => {
|
|
alert('Get Customers Failed: ' + reason);
|
|
});
|
|
}
|
|
|
|
// callback for grid selection
|
|
setSelectedRow(event) {
|
|
if (event) {
|
|
this.selected = event.data;
|
|
}
|
|
|
|
this.selectedPODetail = this.astuteClientService.getPODetail(this.selected.ponum).then((data) => {
|
|
if (data) {
|
|
data.forEach((row) => {
|
|
row.poNum = row.ponum;
|
|
row.serviceTypeName = this.serviceNames[row.serviceTypeId - 1];
|
|
row.rateTypeName = this.rateNames[row.feeTypeId - 1];
|
|
});
|
|
// console.log(this.selectedPODetail);
|
|
this.updateContractAmt();
|
|
if (this.gridColumnApi) {
|
|
this.gridColumnApi.autoSizeAllColumns();
|
|
}
|
|
if (this.detailColumnApi) {
|
|
this.detailColumnApi.autoSizeAllColumns();
|
|
}
|
|
return data;
|
|
} else {
|
|
alert('Get SO detail failed!');
|
|
}
|
|
}, (reason) => {
|
|
alert('Get SO detail failed: ' + reason);
|
|
});
|
|
}
|
|
|
|
// for inline updating
|
|
updateRow(event) {
|
|
const eventData = event.data;
|
|
// console.log(eventData);
|
|
|
|
this.astuteClientService.updatePO(eventData.poNum, eventData).then((data) => {
|
|
if (!data) {
|
|
alert('SO updating failed, check input fields');
|
|
}
|
|
this.refreshData();
|
|
}, (reason) => {
|
|
alert('Update SO failed: ' + reason);
|
|
});
|
|
// this.refreshData();
|
|
}
|
|
updateDetailRow(event) {
|
|
const eventData = event.data;
|
|
// console.log(eventData);
|
|
event.data.serviceTypeId = this.getServiceIdFromName(event.data.serviceTypeName);
|
|
event.data.feeTypeId = this.getFeeIdFromName(event.data.rateTypeName);
|
|
if (event.data.feeTypeId === 1 && event.data.qty > 1) { // fixed fee and qty > 1
|
|
alert('Cannot have a quantity greater than 1 for fixed fee rate type.');
|
|
this.refreshDetailsOfSelected();
|
|
} else {
|
|
// console.log(event.data.serviceTypeId);
|
|
this.astuteClientService.updatePODetail(eventData.poNum, eventData.lineItemNo, eventData).then((data) => {
|
|
if (!data) {
|
|
alert('SO Detail updating failed, check input fields');
|
|
}
|
|
this.refreshDetailsOfSelected();
|
|
}, (reason) => {
|
|
alert('Update SO Detail failed: ' + reason);
|
|
});
|
|
// this.refreshData();
|
|
}
|
|
}
|
|
|
|
// wrappers for PO service methods
|
|
addPo(projNum, ponum, podate, customerid, contractnum, contractamt, title, notes, ref) {
|
|
const poData = {
|
|
'astuteProjectNumber': projNum,
|
|
'poNum': ponum,
|
|
'podate': podate,
|
|
'customerId': customerid,
|
|
'contractNum': contractnum,
|
|
'contractAmt': contractamt,
|
|
'title': title,
|
|
'notes': notes
|
|
};
|
|
// console.log(poData);
|
|
this.astuteClientService.createPO(poData).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
// this.addPODetail(this.newPODetail);
|
|
ref.close();
|
|
} else {
|
|
alert('SO Creation failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
alert('Add SO failed for ' + reason);
|
|
});
|
|
}
|
|
editPo(projNum, ponum, podate, contractnum, contractamt, title, notes, ref) {
|
|
const poData = {
|
|
'astuteProjectNumber': projNum,
|
|
'poNum': ponum,
|
|
'podate': podate,
|
|
'contractNum': contractnum,
|
|
'contractAmt': contractamt,
|
|
'title': title,
|
|
'notes': notes,
|
|
};
|
|
// console.log(poData);
|
|
this.astuteClientService.updatePO(ponum, poData).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
// this.editPODetail(this.selectedPODetail);
|
|
ref.close();
|
|
} else {
|
|
alert('SO updating failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
alert('Update SO failed for ' + reason);
|
|
});
|
|
}
|
|
finalizePO(ponum) {
|
|
this.astuteClientService.finalizePO(ponum).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
alert('SO is now final and ready to be used, you can\'t delete it anymore!');
|
|
} else {
|
|
alert('Finalizing SO failed, check input fields');
|
|
}
|
|
}, reason => {
|
|
alert('Finalizing SO failed: ' + reason);
|
|
});
|
|
}
|
|
deletePO(ponum) {
|
|
if (confirm('Are you sure?')) {
|
|
this.astuteClientService.deletePO(ponum).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
} else {
|
|
alert('Deleting SO failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
alert('Deleting SO failed: ' + reason);
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// wrappers for SO detail service methods
|
|
addEmptyDetail() {
|
|
const emptyData = {
|
|
fee: 0,
|
|
feeTypeId: 1,
|
|
// lineItemNo: 7,
|
|
poNum: this.selected.poNum,
|
|
qty: 1,
|
|
remainingQty: 1,
|
|
serviceDesc: '',
|
|
serviceTypeId: 1
|
|
};
|
|
|
|
// String poNum;
|
|
// int lineItemNo;
|
|
// String serviceDesc;
|
|
// int feeTypeId;
|
|
// Double qty;
|
|
// Double fee;
|
|
// int serviceTypeId;
|
|
// Double remainingQuantity;
|
|
this.astuteClientService.createPODetail(emptyData).then((data) => {
|
|
if (!data) {
|
|
alert('Creating SO detailed failed!');
|
|
}
|
|
this.refreshDetailsOfSelected();
|
|
}, (reason) => {
|
|
alert('Creating SO detailed failed: ' + reason);
|
|
});
|
|
}
|
|
|
|
// open and closing modal-form components
|
|
open(ref) {
|
|
// this.getSelectedRows();
|
|
this.gridColumnApi.autoSizeAllColumns();
|
|
this.detailColumnApi.autoSizeAllColumns();
|
|
ref.open();
|
|
}
|
|
close(ref) {
|
|
// this.newPODetail = [];
|
|
// this.selectedPODetail = [];
|
|
ref.close();
|
|
}
|
|
|
|
// refreshing data methods
|
|
refreshData() {
|
|
// this.astuteClientService.getPOs().then((data) => {
|
|
// if (data) {
|
|
// // this.pos = data;
|
|
// this.rowData = data;
|
|
// this.rowData.forEach((row) => {
|
|
// row.customerName = this.getCustomerNameFromId(row.customerId);
|
|
// row.contractAmtString = formatCurrency(row.contractAmt, 'en-US', '$', 'USD');
|
|
// row.poNum = row.ponum;
|
|
// });
|
|
// this.selected = null;
|
|
// this.updateNewContractAmt();
|
|
// this.updateEditContractAmt();
|
|
// } else {
|
|
// alert('Get SO\'s Failed!');
|
|
// }
|
|
// }, (reason) => {
|
|
// alert('Get SO\'s Failed: ' + reason);
|
|
// });
|
|
this.rowData = this.astuteClientService.getPOs().then((data) => {
|
|
if (data) {
|
|
// this.pos = data;
|
|
data.forEach((row) => {
|
|
row.customerName = this.getCustomerNameFromId(row.customerId);
|
|
row.contractAmtString = formatCurrency(row.contractAmt, 'en-US', '$', 'USD');
|
|
row.poNum = row.ponum;
|
|
});
|
|
this.selected = null;
|
|
this.contractAmount = 0;
|
|
return data;
|
|
} else {
|
|
alert('Get SO\'s Failed!');
|
|
}
|
|
}, (reason) => {
|
|
alert('Get SO\'s Failed: ' + reason);
|
|
});
|
|
}
|
|
refreshDetailsOfSelected() {
|
|
this.setSelectedRow(null);
|
|
}
|
|
updateContractAmt() {
|
|
this.contractAmount = 0;
|
|
if (this.selectedPODetail) {
|
|
this.selectedPODetail.then((detail) => {
|
|
detail.forEach((d) => {
|
|
this.contractAmount += +d.qty * +d.fee;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
// helper methods
|
|
getCurrDate() {
|
|
const d = new Date();
|
|
return this.formatDate(d);
|
|
}
|
|
formatDate(d: Date) {
|
|
let month = '' + (d.getMonth() + 1),
|
|
day = '' + d.getDate(),
|
|
year = d.getFullYear();
|
|
|
|
if (month.length < 2) {
|
|
month = '0' + month;
|
|
}
|
|
if (day.length < 2) {
|
|
day = '0' + day;
|
|
}
|
|
return [year, month, day].join('-');
|
|
}
|
|
getCustomerNameFromId(customerId) {
|
|
let name = '';
|
|
this.customers.forEach((customer) => {
|
|
if (customer.customerId === customerId) {
|
|
name = customer.customerName;
|
|
}
|
|
});
|
|
return name;
|
|
}
|
|
getServiceIdFromName(name) {
|
|
let id = -1;
|
|
this.serviceTypes.forEach((type) => {
|
|
console.log(type.serviceTypeDesc + ' ' + name);
|
|
if (type.serviceTypeDesc === name) {
|
|
id = type.serviceTypeId;
|
|
}
|
|
});
|
|
return id;
|
|
}
|
|
getFeeIdFromName(name: any) {
|
|
let id = -1;
|
|
this.rateTypes.forEach((type) => {
|
|
if (type.feeTypeDesc === name) {
|
|
id = type.feeTypeId;
|
|
}
|
|
});
|
|
return id;
|
|
}
|
|
|
|
// ag grid callbacks
|
|
onGridReady(evt) {
|
|
this.gridApi = evt.api;
|
|
this.gridColumnApi = evt.columnApi;
|
|
}
|
|
onDetailGridReady(evt) {
|
|
this.detailGridApi = evt.api;
|
|
this.detailColumnApi = evt.columnApi;
|
|
}
|
|
resizeColumns(evt) {
|
|
evt.columnApi.autoSizeAllColumns();
|
|
}
|
|
}
|