import {controller, directive} from '../../infrastructure/Dectorators/Components'; import {ITransactionDetail} from '../services/transactionService'; import {Mod} from './transaction.mod'; import {IFlightInformation} from '../services/flightInformationService'; import {IFlightDetail} from '../../core/service/flightService'; import {ITransactionService, TransactionCode, ITransactionConfig} from '../services/transactionService'; import * as InformationService from '../services/flightInformationService'; import {LookupModel, EditorField, LookupEditorField} from '../services/flightInformationService'; export interface TransactionDetailParams extends ng.ui.IStateParamsService { transaction: ITransactionDetail; flight: IFlightDetail; tranAccess: InformationService.IUserAccessModel; columnConfig: Array; } export class TransactionDetail implements ITransactionDetail { constructor(public PublflightId: string, public Id: string, public Code:string, public Name:string, public Quantity: number, public Duration: string, public PONumber: string, public StartTime: string, public EndTime: string, public PhysflightId: string, public Confirmed: boolean, public Cancelled: boolean, public CodeType: number, public Timestamp: number) { } } enum TransactionType { QuantityOnly = 1, TimesOnly, TimeDurationAndQuantity } export class Editor implements InformationService.IFlightEditor { constructor(public Name: string, public Type: string, public Url:string) { } } @controller(Mod, 'transactionDetailController', ['$state', '$scope', '$stateParams', '$ionicPopup', '$rootScope', 'transactionService']) export class Controller { public model: ITransactionDetail; public fields: Array; public editors: Array; public columnConfig: Array; public IsNewAdd: boolean = false; public flightId: string; public physFlightId: string; public lookupModel: LookupModel; public confirmStatus: string; public createStatus: string; public cancelStatus: string; public editStatus: string; public selectedTranCode: TransactionCode; public recalculatingDuration: boolean = false; public recalculationFromDuration: boolean = false; constructor(private $state : ng.ui.IStateService, private $scope: ng.IScope, private $stateParams: TransactionDetailParams, private $ionicPopup: ionic.popup.IonicPopupService, private $rootScope: ng.IRootScopeService, private transactionService: ITransactionService) { this.model = $stateParams.transaction; this.flightId = $stateParams.flight.Id; this.physFlightId = $stateParams.flight.PhysFlightId; if (this.model === null) { this.initNewModel(); this.IsNewAdd = true; } this.columnConfig = $stateParams.columnConfig; if (this.columnConfig === null) { console.log('failed to get column config'); } this.editors = []; this.editors.push({Name: 'readonly', Type: 'readonly', Url: ''}); this.editors.push({Name: 'datetime', Type: 'datetime', Url: ''}); this.editors.push({Name: 'freetext', Type: 'freetext', Url: ''}); this.editors.push({Name: 'lookup', Type: 'lookup', Url: '' }) ; this.createLookupModel(); this.buildFieldsFromModel(); if (!this.IsNewAdd) { var trancode = new TransactionCode(); trancode.CodeType = this.model.CodeType; this.runDisplayLogic(trancode, false); } else { this.editorFor(this.fields[1]); } } private initNewModel() { this.model = new TransactionDetail(this.flightId, '', '', '', 0, '', '', '', '', this.physFlightId, false, false, 1, 0); } public OnStartTimeChanged = (newValue, oldValue) => { if (!this.recalculationFromDuration) { if (oldValue.Value === newValue.Value) { return; } if (this.fieldByName('EndTime').Value !== '') { this.recalculatingDuration = true; this.recalculateDuration(); } } this.recalculationFromDuration = false; } public OnEndTimeChanged = (newValue, oldValue) => { if (!this.recalculationFromDuration) { if (oldValue.Value === newValue.Value) { return; } if (this.fieldByName('StartTime').Value !== '') { this.recalculatingDuration = true; this.recalculateDuration(); } } this.recalculationFromDuration = false; } private recalculateDuration() { var start = moment(this.fieldByName('StartTime').Value); var end = moment(this.fieldByName('EndTime').Value); this.fieldByName('Duration').Value = Math.round(moment.duration(end.diff(start)).asMinutes()).toString(); } public OnDurationChanged = (newValue, oldValue) => { if (!this.recalculatingDuration) { if (oldValue.Value === newValue.Value) { return; } this.recalculationFromDuration = true; if (this.fieldByName('StartTime').Value !== '') { this.recalculateEndTimeFromDurationAndCurrentStartTime(); } else { this.recalculateEndTimeFromStartIsNowPlusDuration(); } } this.recalculatingDuration = false; } private recalculateEndTimeFromDurationAndCurrentStartTime() { var currentStart = moment(this.fieldByName('StartTime').Value); this.fieldByName('EndTime').Value = currentStart.add(this.fieldByName('Duration').Value, 'minutes').toISOString(); } private recalculateEndTimeFromStartIsNowPlusDuration() { var startIsNow = moment(new Date()); this.fieldByName('StartTime').Value = startIsNow.toISOString(); this.fieldByName('EndTime').Value = startIsNow.add(this.fieldByName('Duration').Value, 'minutes').toISOString(); } private addWatches() { this.$scope.$watch('vm.fields[4]', this.OnStartTimeChanged, true); this.$scope.$watch('vm.fields[5]', this.OnEndTimeChanged, true); this.$scope.$watch('vm.fields[6]', this.OnDurationChanged, true); } private createLookupModel() { this.lookupModel = new LookupModel(); this.lookupModel.searchString = ''; this.lookupModel.resultField = 'Name'; this.transactionService.getTransactionCodes() .then((r) => this.onTransactionCodesLoad(r)); var self = this; this.lookupModel.results = []; this.lookupModel.onSelected = (selectedTransactionCode: any) => { self.runDisplayLogic(selectedTransactionCode, true); self.selectedTranCode = selectedTransactionCode; }; this.lookupModel.search = () => { this.lookupModel.results = self.lookupModel.lookupList.filter(item => item.Code.indexOf(self.lookupModel.searchString.toUpperCase()) !== -1 || item.Name.indexOf(self.lookupModel.searchString.toUpperCase()) !== -1); }; } private onTransactionCodesLoad(request: any) : void { this.lookupModel.lookupList = request; this.lookupModel.results = this.lookupModel.lookupList; } private findCode(value: any, searchStr: string) { return value.Name === searchStr; } public runDisplayLogic(selectedTransactionCode, notCreatedYet: boolean) { var trancode = selectedTransactionCode as TransactionCode; var fields = this.fields as EditorField[]; if (notCreatedYet) { this.resetFields(fields); fields[0].Value = selectedTransactionCode.Name; fields[1].Value = selectedTransactionCode.Code; } if (trancode.CodeType === TransactionType.QuantityOnly) { fields[6].Invisible = true; //duration fields[4].Invisible = true; //StartTime fields[5].Invisible = true; //EndTime } else if (trancode.CodeType === TransactionType.TimesOnly) { fields[3].Invisible = true; } } private resetFields(fields: EditorField[]) { for (var i = 0; i < fields.length; i++) { fields[i].Invisible = false; if (fields[i].Editor === 'datetime') { fields[i].Value = ''; } else { fields[i].Value = null; } } } private confirmTransaction() { this.buildModelFromEditorFields(); this.confirmStatus = 'P'; this.transactionService.confirmTransaction(this.model) .then(() => { this.confirmStatus = 'S'; this.$state.go('chroma.flight-detail.transaction-list'); }); } private cancelTransaction() { this.buildModelFromEditorFields(); this.cancelStatus = 'P'; this.transactionService.cancelTransaction(this.model) .then(() => { this.cancelStatus = 'S'; this.$state.go('chroma.flight-detail.transaction-list'); }); } private buildFieldsFromModel() { this.fields = []; this.fields.push(new EditorField('Name', this.model.Name, 'readonly', '', '', '', true, false)); this.fields.push(new LookupEditorField('Code', this.model.Code, this.editorOrReadonly('FLGTTRAN_TRANCATG_CODE', 'lookup'), '', '', this.lookupModel, '', true, false)); this.fields.push(new EditorField('PONumber', this.model.PONumber, this.editorOrReadonly('FLGTTRAN_PO_NUMBER', 'freetext'), '', '', '', true, false)); this.fields.push(new EditorField('Quantity', this.model.Quantity.toString(), this.editorOrReadonly('FLGTTRAN_QUANTITY', 'freetext'), '', '', '', true, false)); this.fields.push(new EditorField('StartTime', this.model.StartTime, this.editorOrReadonly('FLGTTRAN_START_DATE_TIME', 'datetime') , '', '', '', true, false)); this.fields.push(new EditorField('EndTime', this.model.EndTime, this.editorOrReadonly('FLGTTRAN_END_DATE_TIME', 'datetime'), '', '', '', true, false)); this.fields.push(new EditorField('Duration', this.model.Duration, this.editorOrReadonly('FLGTTRAN_DURATION', 'freetext'), '', '', '', true, false)); this.addWatches(); } private editorOrReadonly(fieldName: string, type: string) { var editable = this.columnAccessByFieldName(fieldName); if (editable) { return type; } return 'readonly'; } private columnAccessByFieldName(name: string) : boolean { if (this.IsNewAdd !== true) { return false; //can't edit fields on modify screen } let col : ITransactionConfig = this.columnConfig.filter(item => item.ColumnName.indexOf(name) !== - 1)[0]; return col.Editable; } private createTransaction() { this.buildModelFromEditorFields(); if (this.formIsValid()) { this.transactionService.createTransaction(this.model) .then(() => this.$state.go('chroma.flight-detail.transaction-list') ); } } private formIsValid() : boolean { let editorFields = this.fields as Array; var valid = true; editorFields.forEach(element => { if (element.Invisible === false) { if (!this.validateQuantity(element)) { valid = false; } if (!this.validateTimes(element)) { valid = false; } if (!this.validateTimesAndQuantity(element)) { valid = false; } } }); return valid; } private validateQuantity(element: EditorField) : boolean { if (this.selectedTranCode.CodeType === TransactionType.QuantityOnly || this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { if (element.Name === 'Quantity' && (element.Value === '' || element.Value === null)) { element.Invalid = true; return false; } } return true; } private validateTimes(element: EditorField) : boolean { if (this.selectedTranCode.CodeType === TransactionType.TimesOnly || this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { if ((element.Name === 'StartTime' || element.Name === 'EndTime' || element.Name === 'Duration') && (element.Value === '' || element.Value === null)) { element.Invalid = true; return false; } } return true; } private validateTimesAndQuantity(element: EditorField) : boolean { if (this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { return this.validateTimes(element) && this.validateQuantity(element); } return true; } private buildModelFromEditorFields() { var publflgt = this.model.PublflightId; var Id = this.model.Id; var physFlightId = this.model.PhysflightId; var timestamp = this.model.Timestamp; this.model = new TransactionDetail(publflgt, Id, this.fieldByName('Code').Value, this.fieldByName('Name').Value, Number(this.fieldByName('Quantity').Value), this.fieldByName('Duration').Value, this.fieldByName('PONumber').Value, this.fieldByName('StartTime').Value, this.fieldByName('EndTime').Value, physFlightId, this.model.Confirmed, this.model.Cancelled, 1, timestamp); } private fieldByName(name: string) : IFlightInformation { let field : IFlightInformation = this.fields.filter(item => item.Name.indexOf(name) !== -1)[0]; return field; } public editorFor(field: InformationService.IFlightInformation) { if (field.Editor.toLowerCase() === 'readonly') { return; } let editor = field.Editor.toLowerCase(); let modalScope: any = this.$rootScope.$new(); let editorDefinition: InformationService.IFlightEditor; this.editors.forEach(e => { if (e.Name.toLowerCase() === editor) { editorDefinition = e; } }); modalScope.model = this.model; modalScope.field = field; modalScope.editor = editorDefinition; if (field.Editor.toLowerCase() === 'lookup') { modalScope.lookupModel = this.lookupModel; } modalScope.instance = this.$ionicPopup.show({ templateUrl: `app/flight-detail/editors/${editor}/${editor}-holder.tpl.html`, cssClass: `editor editor-${editor}`, title: `Update ${field.Name}`, scope: modalScope }); } } @directive(Mod, 'chromaTransactionDetail') export class Directive implements ng.IDirective { controller: string = Controller.$componentName; controllerAs: string = 'vm'; templateUrl: string = 'app/flight-detail/transactions/transaction-detail.tpl.html'; restrict: string = 'E'; replace: boolean = false; scope: any = true; }