mirror of
https://github.com/dyiop/astute.git
synced 2025-04-06 21:30:20 -04:00
429 lines
15 KiB
TypeScript
429 lines
15 KiB
TypeScript
import {Component, OnInit, ViewChild} from '@angular/core';
|
|
import {AstuteClientService} from '../services/astute-client-service';
|
|
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";
|
|
|
|
@Component({
|
|
selector: 'app-sales-order',
|
|
templateUrl: './sales-order.component.html',
|
|
styleUrls: ['./sales-order.component.css']
|
|
})
|
|
export class SalesOrderComponent implements OnInit {
|
|
loggedIn: boolean;
|
|
|
|
// 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: (node => !node.data.isFinal), cellEditor: 'emptyErrorEditorComponent'},
|
|
{headerName: 'SO Number', field: 'ponum'},
|
|
// {headerName: 'Customer ID', field: 'customerId'},
|
|
{headerName: 'Customer Name', field: 'customerName'},
|
|
{headerName: 'Contract Number ✎', field: 'contractNum', editable: (node => !node.data.isFinal), cellEditor: 'emptyErrorEditorComponent'},
|
|
{headerName: 'SO Title ✎', field: 'title', editable: (node => !node.data.isFinal), cellEditor: 'emptyErrorEditorComponent'},
|
|
{headerName: 'Contract Amount', field: 'contractAmt', cellRenderer: 'numberFormatterComponent'},
|
|
// {headerName: 'Contract Amount', field: 'contractAmt'},
|
|
{headerName: 'SO Date ✎', field: 'podate', editable: (node => !node.data.isFinal), cellEditor: 'emptyErrorEditorComponent'},
|
|
{headerName: '# of Invoices', field: 'invoiceSequence'},
|
|
{headerName: 'notes ✎', field: 'notes', editable: (node => !node.data.isFinal), cellEditor: 'agLargeTextCellEditor'}
|
|
// {headerName: 'oneInvInDraft', field: 'oneInvInDraft'}
|
|
];
|
|
|
|
gridOptions = {
|
|
rowClassRules: {
|
|
'text-danger': function (params) {
|
|
return !params.data.isFinal;
|
|
},
|
|
'text-primary': function (params) {
|
|
return params.data.isFinal;
|
|
},
|
|
}
|
|
};
|
|
|
|
frameworkComponents = {
|
|
emptyErrorEditorComponent: EmptyErrorEditorComponent,
|
|
numberFormatterComponent: NumberFormatterComponent
|
|
};
|
|
|
|
selected = null; // the selected SO row
|
|
|
|
// data for SO detail grid
|
|
selectedPODetail;
|
|
detailColumnDefs = [
|
|
{headerName: '#', field: 'lineItemNo'},
|
|
{headerName: 'Description ✎', field: 'serviceDesc', editable: (_ => (this.selected && !this.selected.isFinal)),
|
|
cellEditor: 'emptyErrorEditorComponent'},
|
|
{headerName: 'Rate Type ✎', field: 'rateTypeName', editable: (_ => (this.selected && !this.selected.isFinal)),
|
|
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: 'Rate ($) ✎', field: 'fee', editable: (_ => (this.selected && !this.selected.isFinal)),
|
|
cellRenderer: 'numberFormatterComponent'}
|
|
];
|
|
contractAmount = 0; // used to show total amount
|
|
|
|
constructor(private astuteClientService: AstuteClientService, protected toastService: ToastManagerService) {
|
|
}
|
|
|
|
ngOnInit() {
|
|
if (localStorage.getItem('SESSION_ID') && localStorage.getItem('SESSION_USER')) {
|
|
this.loggedIn = true;
|
|
this.astuteClientService.getServiceTypes().then((d) => {
|
|
if (d) {
|
|
this.serviceTypes = d;
|
|
this.serviceTypes.forEach((type) => {
|
|
this.serviceNames.push(type.serviceTypeDesc);
|
|
});
|
|
// console.log(this.serviceNames);
|
|
} else {
|
|
this.notif ('Get service types failed');
|
|
}
|
|
}, reason => {
|
|
this.notif('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 {
|
|
this.notif ('Get rate types failed');
|
|
}
|
|
}, reason => {
|
|
this.notif('Get rate type failed: ' + reason);
|
|
});
|
|
this.astuteClientService.getCustomers().then((customers) => {
|
|
if (customers) {
|
|
this.customers = customers;
|
|
} else {
|
|
this.notif('Get Customers Failed!');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('Get Customers Failed: ' + reason);
|
|
});
|
|
this.refreshData();
|
|
} else {
|
|
this.loggedIn = false;
|
|
}
|
|
}
|
|
|
|
// 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];
|
|
});
|
|
this.updateContractAmt();
|
|
return data;
|
|
} else {
|
|
this.notif('Get SO detail failed!');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('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) {
|
|
this.notif('SO updating failed, check input fields');
|
|
this.refreshData();
|
|
}
|
|
}, (reason) => {
|
|
this.notif('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
|
|
this.notif('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) {
|
|
this.notif('SO Detail updating failed, check input fields');
|
|
this.refreshDetailsOfSelected();
|
|
} else {
|
|
this.updateContractAmt();
|
|
}
|
|
}, (reason) => {
|
|
this.notif('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 {
|
|
this.notif('SO Creation failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('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 {
|
|
this.notif('SO updating failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('Update SO failed for ' + reason);
|
|
});
|
|
}
|
|
finalizePO(ponum) {
|
|
this.astuteClientService.finalizePO(ponum).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
this.notif('SO is now final and ready to be used, you can\'t edit it anymore!');
|
|
} else {
|
|
this.notif('Finalizing SO failed, check input fields');
|
|
}
|
|
}, reason => {
|
|
this.notif('Finalizing SO failed: ' + reason);
|
|
});
|
|
}
|
|
deletePO(ponum) {
|
|
if (confirm('Are you sure?')) {
|
|
this.astuteClientService.deletePO(ponum).then((data) => {
|
|
if (data) {
|
|
this.refreshData();
|
|
} else {
|
|
this.notif('Deleting SO failed, check input fields');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('Deleting SO failed: ' + reason);
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// wrappers for SO detail service methods
|
|
addEmptyDetail(desc: string) {
|
|
const emptyData = {
|
|
fee: 0,
|
|
feeTypeId: 1,
|
|
// lineItemNo: 7,
|
|
poNum: this.selected.poNum,
|
|
qty: 1,
|
|
remainingQty: 1,
|
|
serviceDesc: desc,
|
|
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) {
|
|
this.notif('Creating SO detailed failed!');
|
|
}
|
|
this.refreshDetailsOfSelected();
|
|
}, (reason) => {
|
|
this.notif('Creating SO detailed failed: ' + reason);
|
|
});
|
|
}
|
|
|
|
|
|
// open and closing modal-form components
|
|
open(ref) {
|
|
// this.getSelectedRows();
|
|
ref.open();
|
|
if (this.gridColumnApi) {
|
|
this.gridColumnApi.autoSizeAllColumns();
|
|
}
|
|
if (this.detailColumnApi) {
|
|
this.detailColumnApi.autoSizeAllColumns();
|
|
}
|
|
}
|
|
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 {
|
|
// this.notif('Get SO\'s Failed!');
|
|
// }
|
|
// }, (reason) => {
|
|
// this.notif('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.poNum = row.ponum;
|
|
});
|
|
this.selected = null;
|
|
this.contractAmount = 0;
|
|
return data;
|
|
} else {
|
|
this.notif('Get SO\'s Failed!');
|
|
}
|
|
}, (reason) => {
|
|
this.notif('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();
|
|
}
|
|
|
|
// ** toast notification method
|
|
notif(text: string) {
|
|
this.toastService.show(text, {classname: 'bg-danger text-light'});
|
|
}
|
|
|
|
}
|