const fs = require('fs');
const path = require('path');
const xml2js = require('xml2js');
const AdmZip = require('adm-zip');
const moment = require('moment');
const si = require('systeminformation');
const log = require('loglevel');

const constants = require('../models/constants');
const constantsXml = require('../models/constants-xml');
const enums = require('../models/enums');
const enumsXml = require('../models/enums-xml');

const Pos = require('../models/pos');

class PosTransactionServ {
    constructor () {
        this.axios = global.axiosInstances.axiosAfcInstance;
        this.employeeRoleNameLength = 25;

        this.posModel = Pos;
    }

    status = async (transactionFiles) => {
        try {
            if (typeof transactionFiles == 'undefined') {
                return;
            }
            const xmlBuilder = new xml2js.Builder({xmldec: {version: '1.0', encoding: 'UTF-8'} });
            const xml = await xmlBuilder.buildObject(transactionFiles);
            const res = await this.axios.post('device_comm/transaction/' + process.env.CLIENT_DEVICE_MNEMONIC + '/checkStatus', xml, {headers: {'Content-Type': 'application/xml'}});
            if (typeof res === 'undefined' || res.status >= 400) {
                log.error('status error', res.data);
            }
            return await xml2js.parseStringPromise(res, { explicitRoot: false, explicitArray: false });
        } catch (err) {
            log.error(err);
        }
    }

    create = async (transactionFunc, timestamp) => {
        try {
            let transactionData = {};
            let transactionType;
            let transactionRoot;
            let includeMilliseconds;
            let componentType;
            switch (transactionFunc.function) {
                case 'logOnOff':
                case 'error':
                case 'deviceStatus':
                case 'cashInOut':
                    transactionType = 'OPER';
                    transactionRoot = transactionData.operationalTransactionLog = {};
                    includeMilliseconds = true;
                break;
                case 'cancellation':
                case 'ticketReversal':
                case 'ticket':
                case 'blockUnblock':
                case 'topUp':
                case 'penalty':
                case 'salesOrder':
                case 'accountPayment':
                    transactionType = 'TICK';
                    transactionRoot = transactionData.ticketTransactionLog = {};
                    includeMilliseconds = true;
                break;
                case 'summaryOpenClose':
                    transactionType = 'SUMM';
                    transactionRoot = transactionData.summaryTransactionLog = {};
                    includeMilliseconds = false;
                break;
                case 'smartcard':
                    transactionType = 'ATRAN';
                    transactionRoot = transactionData.accountTransactionLog = {};
                    includeMilliseconds = true;
                break;
                case 'smartCardIinitializeIssue':
                case 'smartCardContract':
                case 'smartCardAction':
                case 'smartCardBlockUnblock':
                case 'smartCardRemoveContract':
                case 'smartCardChangeRider':
                    transactionType = 'TRAN';
                    transactionRoot = transactionData.smartCardTransactionLog = {};
                    includeMilliseconds = true;
                break;
                case 'penaltyIssue':
                    transactionType = 'TEVT';
                    transactionRoot = transactionData.taskEvent = {};
                    includeMilliseconds = true;
                break;
            }

            if (typeof global.currentPosData == undefined) {
                global.currentPosData = await this.posModel.findOne({});
            }

            transactionRoot.$ = {'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', 'timestamp': timestamp.slice(0,-5)};
            Object.assign(transactionRoot, {deviceInformation: await this.deviceInformation(transactionFunc.component)});
            Object.assign(transactionRoot, {locationInformation: await this.locationInformation()});
            Object.assign(transactionRoot, await this[transactionFunc.function](transactionFunc.parameters));

            const xmlBuilder = new xml2js.Builder({xmldec: {version: '1.0', encoding: 'UTF-8'} });
            const xml = await xmlBuilder.buildObject(transactionData);

            const deviceType = (transactionType != 'TEVT') ? process.env.CLIENT_DEVICE_MNEMONIC : 'HCV';
            const deviceId = global.currentPosData.deviceId;
            const versionId = (includeMilliseconds) ? moment.utc(timestamp).format('YYMMDDHHmmss.SSS') : moment.utc(timestamp).format('YYMMDDHHmmss');
            const fileName = [transactionType, deviceType, deviceId, versionId].join('_')+'.xml';
            const filePath = path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_UNSENT, fileName);
            fs.writeFileSync(filePath, xml);

            return {
                fileName: fileName,
                filePath: filePath
            };
        } catch (err) {
            log.error(err);
        }
    }

    upload = async (file) => {
        try {
            const zip = new AdmZip();
            zip.addLocalFile(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_UNSENT, file));
            const zippedXmlStream = zip.toBuffer();
            const res = await this.axios.post('device_comm/transaction/' + process.env.CLIENT_DEVICE_MNEMONIC + '/upload', zippedXmlStream, {headers: {'Content-Type': 'application/zip'}});
            if (typeof res === 'undefined' || res.status >= 400) {
                log.error('upload error', res.data);
            }
            if (typeof res === 'string' || (typeof res.data === 'string' && res.data !== '')) {
                const status = await xml2js.parseStringPromise((typeof res === 'string') ? res : res.data, { explicitRoot: false, explicitArray: false });
                if (status && !status.error && !status.file.error) {
                    fs.renameSync(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_UNSENT, file), path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_SENT, file));
                    if (process.env.POS_TRANSACTIONS_DELETE_SENT == 'true') {
                        fs.unlinkSync(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_SENT, file));
                    }
                    return constants.transacStatus.sent;
                } else {
                    fs.renameSync(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_UNSENT, file), path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_CORRUPTED, file));
                    return constants.transacStatus.corrupted;
                }
            }
            return constants.transacStatus.unsent;
        } catch (err) {
            log.error(err);
        }
    }

    logOnOff = async (parameters) => {
        try {
            return {
                operationalInformation: {
                    logOnOffInformation: await this.logOnOffInformation(parameters.logOnOff)
                }
            };
        } catch (err) {
            log.error(err);
        }
    }

    error = async (parameters) => {
        try {
            return {
                operationalInformation: {
                    errorInformation: await this.errorInformation(parameters.error)
                }
            };
        } catch (err) {
            log.error(err);
        }
    }

    deviceStatus = async (parameters) => {
        try {
            const cpu = await si.currentLoad();
            const mem = await si.mem();
            const corrupted = fs.readdirSync(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_CORRUPTED));
            const unknown = fs.readdirSync(path.join(process.cwd(), process.env.FOLDER_TRANSACTIONS_UNKNOWN));

            return {
                operationalInformation: {
                    deviceStatusInformation: {
                        deviceCounters: {
                            deviceCounter: [{
                                deviceCounterName: 'cpuUtilizationAverage',
                                deviceCounterValue: parseInt(cpu.currentLoad).toFixed(0)
                            },
                            {
                                deviceCounterName: 'memoryUtilizationAverage',
                                deviceCounterValue: Math.abs(mem.free / 1024)
                            },
                            {
                                deviceCounterName: 'corruptedTransactions',
                                deviceCounterValue: corrupted.length
                            },
                            {
                                deviceCounterName: 'unknownTransactions',
                                deviceCounterValue: unknown.length
                            }]
                        },
                        components : {
                            component: [{
                                componentGroup: constantsXml.componentGroup.hardware,
                                componentName: 'SC Reader',
                                componentType: constantsXml.componentType.smartCardReader,
                                componentID: enums.componentTypes.smartCardReader,
                                componentCounters: {
                                    componentCounter: [{
                                        componentCounterName: constantsXml.componentCounterNames.succefullTransactions,
                                        componentCounterValue: global.currentPosData.componentCounter[constantsXml.componentType.smartCardReader]['ok']
                                    },
                                    {
                                        componentCounterName: constantsXml.componentCounterNames.unsuccefullTransactions,
                                        componentCounterValue: global.currentPosData.componentCounter[constantsXml.componentType.smartCardReader]['err']
                                    }]
                                }
                            },
                            {
                                componentGroup: constantsXml.componentGroup.hardware,
                                componentName: 'Printer',
                                componentType: constantsXml.componentType.ticketPrinter,
                                componentID: enums.componentTypes.ticketPrinter,
                                componentCounters: {
                                    componentCounter: [{
                                        componentCounterName: constantsXml.componentCounterNames.ticketsPrinted,
                                        componentCounterValue: global.currentPosData.componentCounter[constantsXml.componentType.ticketPrinter]['ok']
                                    }]
                                }
                            },
                            {
                                componentGroup: constantsXml.componentGroup.hardware,
                                componentName: 'Scanner',
                                componentType: constantsXml.componentType.documentScanner,
                                componentID: enums.componentTypes.documentScanner,
                                componentCounters: {
                                    componentCounter: [{
                                        componentCounterName: constantsXml.componentCounterNames.documentsScanned,
                                        componentCounterValue: global.currentPosData.componentCounter[constantsXml.componentType.documentScanner]['ok']
                                    }, {
                                        componentCounterName: constantsXml.componentCounterNames.error,
                                        componentCounterValue: global.currentPosData.componentCounter[constantsXml.componentType.documentScanner]['err']
                                    }]
                                }
                            }]
                        }
                    }
                }
            };
        } catch (err) {
            log.error(err);
        }
    }

    cashInOut = async (parameters) => {
        try {
            return {
                operationalInformation: {
                    cashTransactionLog: {
                        cashInformation: await this.cashInformation(parameters.cash),
                        cashCollectionInformation: await this.cashCollectionInformation(parameters.collection),
                        cashContainerStatusInformation: await this.cashContainerStatusInformation(parameters.container)
                    }
                }
            };
        } catch (err) {
            log.error(err);
        }
    }

    cancellation = async (parameters) => {
        try {
            let data = {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                ticketSnapshot: await this.ticketSnapshot(parameters.ticket)
            };

            if (['oman'].includes(process.env.CLIENT_NAME)) {
                /*if (data.financialTransaction.fareItemCategory != constantsXml.fareItemCategory.fareProduct) {
                    if (data.financialTransaction.fareItemCategory != constantsXml.fareItemCategory.fareEpurse) {
                        if (data.financialTransaction.fareItemCategory != constantsXml.fareItemCategory.fareJourneyGroup) {
                            if (data.financialTransaction.fareItemCategory == constantsXml.fareItemCategory.fareSingleRideGroup) {
                                data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareSingleRideGroup;
                                data.financialTransaction.fareItemType = constantsXml.fareItemType.singleRideGroupElectronicTicket;
                            } else if (data.financialTransaction.fareItemCategory == constantsXml.fareItemCategory.farePenaltyItem) {
                                data.financialTransaction.fareItemName = constantsXml.fareItemName.na;
                                data.financialTransaction.payingRiderAccountId = parameters.financial.payingRiderAccountId;
                                data.financialTransaction.itemReferenceId = parameters.financial.itemReferenceId;
                                data.financialTransaction.penaltyFee = parameters.financial.cumulativeFareOrProductPrice;
                                //data.validationInformation = await this.validationInformation();
                            } else {
                                if (data.financialTransaction.fareItemName == constantsXml.fareItemName.singleRideTicket) {
                                    if (data.financialTransaction.fareItemCategory == constantsXml.fareItemCategory.fareReturnSingleRide) {
                                        if (data.financialTransaction.fareItemType == constantsXml.fareItemType.returnSingleRideElectronicTicket) {
                                            data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareReturnSingleRide;
                                            data.financialTransaction.fareItemType = constantsXml.fareItemType.returnSingleRideElectronicTicket;
                                        } else {
                                            data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareReturnSingleRide;
                                            data.financialTransaction.fareItemType = constantsXml.fareItemType.returnSingleRideTicket;
                                        }
                                    } else {
                                        if (data.financialTransaction.fareItemType == constantsXml.fareItemType.singleRideElectronicTicket) {
                                            data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareSingleRide;
                                            data.financialTransaction.fareItemType = constantsXml.fareItemType.singleRideElectronicTicket;
                                        } else {
                                            data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareSingleRide;
                                            data.financialTransaction.fareItemType = constantsXml.fareItemType.singleRideTicket;
                                        }
                                    }
                                } else {
                                    delete data.fareModelInformation;
                                    data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareJourneyGroup;
                                    data.financialTransaction.fareItemType = constantsXml.fareItemType.journeyTicket;
                                    data.financialTransaction.fareItemName = constantsXml.fareItemName.zoneTicketFare;
                                }
                            }
                        } else {
                            if (data.financialTransaction.fareItemName == constantsXml.fareItemType.singleRideTicket) {
                                data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareSingleRideGroup;
                                data.financialTransaction.fareItemType = constantsXml.fareItemType.singleRideGroupElectronicTicket;
                            } else {
                                delete data.fareModelInformation;
                                data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareJourneyGroup;
                                data.financialTransaction.fareItemType = constantsXml.fareItemType.journeyGroupElectronicTicket;
                                data.financialTransaction.fareItemName = constantsXml.fareItemName.zoneTicketFare;
                            }
                        }
                    } else {
                        delete data.fareModelInformation;
                        data.financialTransaction.activityType = constantsXml.activityType.debit;
                        data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareEpurse;
                        data.financialTransaction.fareItemType = constantsXml.fareItemType.refundEpurseAccount;
                        data.financialTransaction.fareItemName = constantsXml.fareItemName.na;
                        data.financialTransaction.reasonInformation.reasonId = data.financialTransaction.creditReversalReason.reasonId;
                        data.financialTransaction.reasonInformation.reasonName = data.financialTransaction.creditReversalReason.reasonName;
                    }
                } else {
                    if (data.financialTransaction.anonimusLuggage == true) {
                        data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareProduct;
                        data.financialTransaction.fareItemType = constantsXml.fareItemType.productAccount;
                    } else {
                        delete data.financialTransaction.relatedTransactionInformation;
                        data.financialTransaction.fareItemCategory = constantsXml.fareItemCategory.fareProduct;
                        data.financialTransaction.fareItemType = constantsXml.fareItemType.productTicket;
                    }
                }*/
                if (data.financialTransaction.fareItemCategory == constantsXml.fareItemCategory.fareEpurse) {
                    delete data.financialTransaction.passengerDetails;
                    delete data.ticketSnapshot;
                }

                return data;
            }

            if (['lit', 'kuwait', 'hafil', 'sharjah', 'mok'].includes(process.env.CLIENT_NAME)) {
                if (data.financialTransaction.fareItemCategory == constantsXml.fareItemCategory.fareEpurse) {
                    delete data.financialTransaction.passengerDetails;
                    delete data.ticketSnapshot;
                }
            }

            if (parameters.booking && global.currentPosData.hasReservation) {
                data.bookingInformation = await this.bookingInformation(parameters.booking);
            }

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    ticketReversal = async (parameters) => {
        try {
            let data = {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                ticketSnapshot: await this.ticketSnapshot(parameters.ticket)
            };

            // delete data.financialTransaction.paymentInstrument;

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    ticket = async (parameters) => {
        try {
            let data = {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                ticketSnapshot: await this.ticketSnapshot(parameters.ticket)
            };

            if (['oman'].includes(process.env.CLIENT_NAME)) {
                if (data.financialTransaction.fareItemCategory != constantsXml.fareItemCategory.fareProduct) {
                    delete data.financialTransaction.relatedTransactionInformation;
                } else {
                    if (data.financialTransaction.fareItemType != constantsXml.fareItemType.productTicket) {
                        delete data.financialTransaction.passengerDetails;
                        data.ticketSnapshot.noOfPassengersFirst = 0;
                        data.ticketSnapshot.issuedBoardingStopCode = 0;
                        data.ticketSnapshot.issuedAlightingStopCode = 0;
                        delete data.ticketSnapshot.issuedBoardingStationCode;
                        delete data.ticketSnapshot.issuedAlightingStationCode;
                        data.ticketSnapshot.allowedStagesOrZonesNumber = 0;
                    } else {
                        if (data.financialTransaction.anonimusLuggage == 'true') {
                            delete data.financialTransaction.passengerDetails;
                            data.ticketSnapshot.noOfPassengersFirst = 0;
                            data.ticketSnapshot.issuedBoardingStopCode = 0;
                            data.ticketSnapshot.issuedAlightingStopCode = 0;
                            delete data.ticketSnapshot.issuedBoardingStationCode;
                            delete data.ticketSnapshot.issuedAlightingStationCode;
                            data.ticketSnapshot.allowedStagesOrZonesNumber = 0;
                        } else {
                            delete data.financialTransaction.passengerDetails;
                            delete data.financialTransaction.relatedTransactionInformation;
                            data.ticketSnapshot.noOfPassengersFirst = 0;
                            data.ticketSnapshot.issuedBoardingStopCode = 0;
                            data.ticketSnapshot.issuedAlightingStopCode = 0;
                            delete data.ticketSnapshot.issuedBoardingStationCode;
                            delete data.ticketSnapshot.issuedAlightingStationCode;
                            data.ticketSnapshot.allowedStagesOrZonesNumber = 0;
                        }
                    }
                }

                if (parameters.avl) {
                    data.avlInformation = await this.avlInformation(parameters.avl);
                }

                return data;
            }

            if (parameters.booking && global.currentPosData.hasReservation) {
                data.bookingInformation = await this.bookingInformation(parameters.booking);
            }

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            if (parameters.order && global.currentPosData.hasSalesOrder) {
                data.salesOrderInformation = await this.salesOrderInformation(parameters.order);
            }

            if (parameters.custom) {
                data.customTransactionParameters = await this.customTransactionParameters(parameters.custom);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    blockUnblock = async (parameters) => {
        try {
            return {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation()
            };
        } catch (err) {
            log.error(err);
        }
    }

    topUp = async (parameters) => {
        try {
            return {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation()
            };
        } catch (err) {
            log.error(err);
        }
    }

    accountPayment = async (parameters) => {
        try {
            let data = {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation()
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            if (parameters.order && global.currentPosData.hasSalesOrder) {
                data.salesOrderInformation = await this.salesOrderInformation(parameters.order);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    penalty = async (parameters) => {
        try {
            return {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation()
            };
        } catch (err) {
            log.error(err);
        }
    }

    salesOrder = async (parameters) => {
        try {
            let data = {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                salesOrderInformation: await this.salesOrderInformation(parameters.order)
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    summaryOpenClose = async (parameters) => {
        try {
            return {
                summaryInformation: await this.summaryInformation(parameters.summary)
            };
        } catch (err) {
            log.error(err);
        }
    }

    smartcard = async (parameters) => {
        try {
            return {
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation()
            };
        } catch (err) {
            log.error(err);
        }
    }

    smartCardIinitializeIssue = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card)
            };

            if (parameters.card.issuing == constantsXml.smartCardIssueType.reIssue) {
                delete data.cardOperation;
            }

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            if (parameters.card.cardHolderInfoBasic) {
                data.cardHolderInfoBasic = await this.cardHolderInfoBasic(parameters.card.cardHolderInfoBasic);
            }
            if (parameters.card.cardHolderInfoExtended) {
                data.cardHolderInfoExtended = await this.cardHolderInfoExtended(parameters.card.cardHolderInfoExtended);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    cardHolderInfoBasic = async (cardHolderInfo) => {
        try {
            return {
                cardHolderType: cardHolderInfo.type,
                cardHolderGender: cardHolderInfo.gender,
                cardHolderFirstName: cardHolderInfo.firstName,
                cardHolderLastName: cardHolderInfo.lastName,
                cardHolderDayOfBirth: moment.utc(cardHolderInfo.dayOfBirth).toISOString()
            };
        } catch (err) {
            log.error(err);
        }
    }

    cardHolderInfoExtended = async (cardHolderInfo) => {
        try {
            return {
                cardHolderAddressLine1: cardHolderInfo.addressLine1,
                cardHolderAddressLine2: cardHolderInfo.addressLine2,
                cardHolderAddressLine3: cardHolderInfo.addressLine3,
                cardHolderCity: cardHolderInfo.city,
                cardHolderPostalCode: cardHolderInfo.postalCode,
                cardHolderCountryCode: cardHolderInfo.countryCode,
                cardHolderCountryProvince: cardHolderInfo.countryProvince,
                cardHolderPhoneNumber: cardHolderInfo.phoneNumber,
                cardHolderIdentificationType: cardHolderInfo.identificationType,
                cardHolderIdentificationId: cardHolderInfo.identificationId,
                cardHolderIdentificationName: cardHolderInfo.identificationName,
                cardHolderIdentificationExpiry: moment.utc(cardHolderInfo.identificationExpiry).toISOString()
            };
        } catch (err) {
            log.error(err);
        }
    }

    smartCardContract = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card)
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    smartCardAction = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card),
                actionResponse: await this.actionResponse(parameters.action)
            };

            if (parameters.action.name == 'refundableDeposit') {
                delete data.cardOperation;
            }

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    smartCardBlockUnblock = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card)
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    smartCardRemoveContract = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card)
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    smartCardChangeRider = async (parameters) => {
        try {
            let data = {
                financialTransaction: await this.financialTransaction(parameters.financial),
                validationInformation: await this.validationInformation(),
                cardReference: await this.cardReference(parameters.card),
                cardSnapshot: await this.cardSnapshot(parameters.card),
                cardOperation: await this.cardOperation(parameters.card)
            };

            if (parameters.avl) {
                data.avlInformation = await this.avlInformation(parameters.avl);
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    deviceInformation = async (component) => {
        try {
            if (typeof component === 'object' && component !== null) {
                return {
                    deviceType: component.deviceType,
                    deviceVersion: component.deviceVersion,
                    deviceSoftwareVersion: component.deviceSoftwareVersion,
                    deviceID: component.deviceId,
                    deviceSharedId: component.deviceSharedId,
                    deviceComponentType: component.deviceComponentType,
                    deviceComponentID: component.deviceComponentId,
                    deviceDutyCode: (component.deviceDutyCode) ? component.deviceDutyCode : '',
                    terminalId: component.terminalId,
                    deviceTransactionCounter: component.deviceTransactionCounter,
                    faretableTimestamp: moment.utc(component.faretableTimestamp).toISOString(),
                    revenueMode: constantsXml.revenueMode.inService,
                    operationMode: component.operationMode,
                    operatorRef: component.operatorRef,
                    operatorTypeExternalID: (component.operatorTypeExternalId) ? component.operatorTypeExternalId : 0,
                    operatorTypeName: (component.operatorTypeName) ? component.operatorTypeName.slice(0, this.employeeRoleNameLength) : 'unattended',
                    operatorSalesChannel: constantsXml.salesChannel.spos
                };
            }

            let data = {
                deviceType: constantsXml.deviceType.officePos,
                deviceVersion: global.currentPosData.deviceVersion,
                deviceSoftwareVersion: global.currentPosData.appVersion,
                deviceID: global.currentPosData.deviceId,
                deviceSharedId: global.currentPosData.deviceSharedId,
                deviceComponentType: constantsXml.componentType[component],
                deviceComponentID: enumsXml.componentType[component],
                deviceDutyCode: (global.currentEmployeeData.employeeSessionId) ? global.currentEmployeeData.employeeSessionId : '',
                terminalId: global.currentPosData.terminalId,
                deviceTransactionCounter: global.currentPosData.transactionCounter,
                faretableTimestamp: moment.utc(global.currentPosData.faretableTimestamp).toISOString(),
                revenueMode: constantsXml.revenueMode.inService,
                operationMode: constantsXml.operationMode.issuing,
                operatorRef: (global.currentEmployeeData.employeeId) ? global.currentEmployeeData.employeeId : 'unattended',
                operatorTypeExternalID: (global.currentEmployeeData.employeeRoleId) ? global.currentEmployeeData.employeeRoleId : 0,
                operatorTypeName: (global.currentEmployeeData.employeeRoleName) ? global.currentEmployeeData.employeeRoleName.slice(0, this.employeeRoleNameLength) : 'unattended',
                operatorSalesChannel: constantsXml.salesChannel.spos
            };

            if (global.currentPosData.publicTransportOrganizationRef) {
                data.publicTransportOrganizationRef = 'publicTransportOrganizationRef';
            }

            if (global.currentPosData.securityElementId) {
                data.securityElementId = global.currentPosData.securityElementId;
                data.securityElementTransactionCounter = global.currentPosData.securityElementTransactionCounter;
            }

            if (!component) {
                delete data.deviceComponentType;
                delete data.deviceComponentID;
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    locationInformation = async () => {
        try {
            return {
                organizationExternalID: global.currentPosData.organizationExternalId,
                organizationName: global.currentPosData.organization,
                locationExternalID: global.currentPosData.locationExternalId,
                locationName: global.currentPosData.location
            };
        } catch (err) {
            log.error(err);
        }
    }

    avlInformation = async (route) => {
        try {
            let data = {
                routeExternalId: route.externalId,
                routeName: route.name,
                routeDestination: route.destination,
                routeVariant: route.variant,
                routeVersion: route.version
            };

            if (route.locationLongitude) {
                data.vehicleLocationLongitude = route.locationLongitude;
            }

            if (route.locationLatitude) {
                data.vehicleLocationLatitude = route.locationLatitude;
            }

            if (route.tripId) {
                data.tripId = route.tripId;
            }

            if (route.tripStartTimestamp) {
                data.tripStartTimestamp = moment.utc(route.tripStartTimestamp).toISOString();
            }

            if (route.tripEstimatedEndTimestamp) {
                data.tripEstimatedEndTimestamp = moment.utc(route.tripEstimatedEndTimestamp).toISOString();
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    fareModelInformation = async (transit) => {
        try {
            return {
                routeTypeExternalID: transit.externalId,
                routeTypeName: transit.name,
                fareSystemModel: transit.fareSystemModel,
                routeSystemType: transit.routeSystemType
            };
        } catch (err) {
            log.error(err);
        }
    }

    financialTransaction = async (financial) => {
        try {
            let data = {
                activityType: financial.activityType,
                fareItemCategory: financial.fareItemCategory,
                fareItemType: financial.fareItemType,
                fareItemExternalID: financial.fareItemExternalId,
                fareItemName: financial.fareItemName,
                payingRiderTypeExternalID: (financial.payingRiderTypeExternalId) ? financial.payingRiderTypeExternalId : constants.defaults.accountId,
                payingRiderTypeName: (financial.payingRiderTypeName) ? financial.payingRiderTypeName : constants.defaults.accountName,
                cumulativeFareOrProductPrice: (financial.cumulativeFareOrProductPrice).toFixed(),
                totalPaymentInCents: (financial.totalPaymentInCents).toFixed(),
                paymentInstrument: financial.paymentInstrument,
                paymentMethod: financial.paymentMethod,
                currencyCode: financial.currencyCode
            };

            if (financial.fareItemProductType) {
                data.fareItemProductType = financial.fareItemProductType;
            }

            if (financial.fareItemIssuedNumber) {
                data.fareItemIssuedNumber = financial.fareItemIssuedNumber;
            }

            if (financial.fareItemIssuedExpirationTimeStamp) {
                data.fareItemIssuedExpirationTimeStamp = moment.utc(financial.fareItemIssuedExpirationTimeStamp).toISOString();
            }

            if (financial.payingRiderAccountId) {
                data.payingRiderAccountId = financial.payingRiderAccountId;
            }

            if (financial.fareItemPurchasedStagesOrZones) {
                data.fareItemPurchasedStagesOrZones = financial.fareItemPurchasedStagesOrZones;
            }

            if (financial.itemReferenceId) {
                data.itemReferenceId = financial.itemReferenceId;
            }

            if (financial.penaltyFee) {
                data.penaltyFee = (financial.penaltyFee).toFixed();
            }

            if (financial.paymentInstrumentTransactionId) {
                data.paymentInstrumentTransactionId = financial.paymentInstrumentTransactionId;
            }

            if (financial.passengerDetails && financial.passengerDetails.passengerRiderTypeExternalId) {
                data.passengerDetails = {
                    passengerDetail: {
                        passengerRiderTypeExternalID: financial.passengerDetails.passengerRiderTypeExternalId,
                        passengerRiderTypeName: financial.passengerDetails.passengerRiderTypeName,
                        noOfPassengers: financial.passengerDetails.noOfPassengers,
                        passengerBaseFare: (financial.passengerDetails.passengerBaseFare).toFixed()
                    }
                };
            }

            if (financial.passengerDetails && financial.passengerDetails.passengerCorrectionFareDetails) {
                data.passengerDetails.passengerDetail.passengerCorrectionFareDetails = {
                    passengerCorrectionFareDetail: {
                        calculationSequenceCounter: financial.passengerDetails.passengerCorrectionFareDetails.calculationSequenceCounter,
                        fareAdjustmentId: financial.passengerDetails.passengerCorrectionFareDetails.fareAdjustmentId,
                        fareAdjustmentType: financial.passengerDetails.passengerCorrectionFareDetails.fareAdjustmentType,
                        fareAdjustmentName: financial.passengerDetails.passengerCorrectionFareDetails.fareAdjustmentName,
                        //inputBaseFare: financial.passengerDetails.passengerCorrectionFareDetails.inputBaseFare,
                        //inputProductPrice: financial.passengerDetails.passengerCorrectionFareDetails.inputProductPrice,
                        //inputTransferFare: financial.passengerDetails.passengerCorrectionFareDetails.inputTransferFare,
                        //inputAddedFare: financial.passengerDetails.passengerCorrectionFareDetails.inputAddedFare,
                        //fixedAmountCorrectionValue: financial.passengerDetails.passengerCorrectionFareDetails.fixedAmountCorrectionValue,
                        //percentageCorrectionValue: financial.passengerDetails.passengerCorrectionFareDetails.percentageCorrectionValue,
                        //correctedBaseFare: financial.passengerDetails.passengerCorrectionFareDetails.correctedBaseFare,
                        //correctedProductPrice: financial.passengerDetails.passengerCorrectionFareDetails.correctedProductPrice,
                        //correctedTransferFare: financial.passengerDetails.passengerCorrectionFareDetails.correctedTransferFare,
                        //correctedAddedFare: financial.passengerDetails.passengerCorrectionFareDetails.correctedAddedFare,
                        //correctionFare: financial.passengerDetails.passengerCorrectionFareDetails.correctionFare
                    }
                };

                if (financial.passengerDetails.passengerCorrectionFareDetails.inputBaseFare) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.inputBaseFare = (financial.passengerDetails.passengerCorrectionFareDetails.inputBaseFare).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.inputProductPrice) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.inputProductPrice = (financial.passengerDetails.passengerCorrectionFareDetails.inputProductPrice).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.fixedAmountCorrectionValue) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.fixedAmountCorrectionValue = (financial.passengerDetails.passengerCorrectionFareDetails.fixedAmountCorrectionValue).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.percentageCorrectionValue) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.percentageCorrectionValue = (financial.passengerDetails.passengerCorrectionFareDetails.percentageCorrectionValue).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.correctedBaseFare) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.correctedBaseFare = (financial.passengerDetails.passengerCorrectionFareDetails.correctedBaseFare).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.correctedProductPrice) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.correctedProductPrice = (financial.passengerDetails.passengerCorrectionFareDetails.correctedProductPrice).toFixed();
                }

                if (financial.passengerDetails.passengerCorrectionFareDetails.correctionFare) {
                    data.passengerDetails.passengerDetail.passengerCorrectionFareDetails.passengerCorrectionFareDetail.correctionFare = (financial.passengerDetails.passengerCorrectionFareDetails.correctionFare).toFixed();
                }
            }

            if (financial.boardingInformation) {
                data.boardingInformation = await this.boardingInformation(financial.boardingInformation);
            }

            if (financial.taxInvoiceInformation) {
                data.taxInvoiceInformation = await this.taxInvoiceInformation(financial.taxInvoiceInformation);
            }

            if (financial.totalVatInCents) {
                data.totalVatInCents = (financial.totalVatInCents).toFixed();
            }

            if (financial.vatAddedToTotalPayment) {
                data.vatAddedToTotalPayment = financial.vatAddedToTotalPayment;
            }

            if (financial.vatDetails) {
                let vatDetails = (Array.isArray(financial.vatDetails)) ? financial.vatDetails : Array(financial.vatDetails);
                data.vatDetails = {
                    vatDetail: []
                };
                for (let i=0; i<vatDetails.length; i++) {
                    data.vatDetails.vatDetail.push({
                        taxableAmountInCents: (vatDetails[i].taxableAmountInCents).toFixed(),
                        vatRate: (vatDetails[i].vatRate).toFixed(),
                        vatInCents: (vatDetails[i].vatInCents).toFixed()
                    });
                }
            }

            if (financial.relatedTransactionInformation) {
                data.relatedTransactionInformation = financial.relatedTransactionInformation;
            }

            if (financial.reasonInformation && financial.reasonInformation.reasonId) {
                data.reasonInformation = financial.reasonInformation;
            }

            if (financial.accountIdentifierMediaId) {
                data.accountIdentifierMediaId = financial.accountIdentifierMediaId;
            }

            if (financial.accountIdentifierMediaType) {
                data.accountIdentifierMediaType = financial.accountIdentifierMediaType;
            }

            if (financial.accountIdentifierMediaTechnologyType) {
                data.accountIdentifierMediaTechnologyType = financial.accountIdentifierMediaTechnologyType;
            }

            if (financial.bookingDiscount && financial.bookingDiscount.dynamicDiscountCode) {
                data.dynamicDiscountId = financial.bookingDiscount.dynamicDiscountCode;
            }

            if (financial.bookingDiscount && financial.bookingDiscount.dynamicDiscountType) {
                data.dynamicDiscountType = financial.bookingDiscount.dynamicDiscountType;
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    validationInformation = async () => {
        try {
            return {
                validationStatus: constantsXml.validationStatus.validationSuccessful,
                denyReason: constantsXml.denyReason.unknown
            };
        } catch (err) {
            log.error(err);
        }
    }

    logOnOffInformation = async (operational) => {
        try {
            return {
                desiredState: operational.desiredState,
                logOnOffMethod: operational.logOnOffMethod,
                mode: operational.mode,
                finalState: operational.finalState
            };
        } catch (err) {
            log.error(err);
        }
    }

    errorInformation = async (error) => {
        try {
            return {
                errorCode: error.errorCode,
                errorStatus: error.errorStatus,
                errorDetails: error.errorDetails
            };
        } catch (err) {
            log.error(err);
        }
    }

    summaryInformation = async (summary) => {
        try {
            let data = {
                summaryActivityType: summary.summaryActivityType,
                summaryType: constantsXml.summaryType.workingInterval,
                summaryReferenceByDevice: global.currentPosData.deviceId,
                summaryReferenceByOperator: (global.currentEmployeeData.employeeId) ? global.currentEmployeeData.employeeId : 'unattended',
                summaryOpenTimestamp: (global.currentEmployeeData.employeeLoginTime) ? moment.utc(global.currentEmployeeData.employeeLoginTime).toISOString() : moment.utc().toISOString(),
                summaryOpenOperatorRef: (global.currentEmployeeData.employeeId) ? global.currentEmployeeData.employeeId : 'unattended',
                summaryOpenOperatorTypeExternalID: (global.currentEmployeeData.employeeRoleId) ? global.currentEmployeeData.employeeRoleId : 0,
                summaryOpenOperatorTypeName: (global.currentEmployeeData.employeeRoleName) ? global.currentEmployeeData.employeeRoleName.slice(0, this.employeeRoleNameLength) : 'unattended',
                currencyCode: global.currentPosData.currencyCode
            };

            if (summary.summaryActivityType == constantsXml.summaryActivityType.closeSummary) {
                Object.assign(data, {
                    summaryCloseTimestamp: (global.currentEmployeeData.employeeLogoutTime) ? moment.utc(global.currentEmployeeData.employeeLogoutTime).toISOString() : moment.utc().toISOString(),
                    summaryCloseOperatorRef: (global.currentEmployeeData.employeeId) ? global.currentEmployeeData.employeeId : 'unattended',
                    summaryCloseOperatorTypeExternalID: (global.currentEmployeeData.employeeRoleId) ? global.currentEmployeeData.employeeRoleId : 0,
                    summaryCloseOperatorTypeName: (global.currentEmployeeData.employeeRoleName) ? global.currentEmployeeData.employeeRoleName.slice(0, this.employeeRoleNameLength) : 'unattended'
                });
            }

            Object.assign(data, {
                summaryCashCollected: (summary.summaryCashCollected).toFixed(),
                summaryRevenueCollected: (summary.summaryRevenueCollected).toFixed(),
                summaryCashCanceled: (summary.summaryCashCanceled).toFixed(),
                summaryRevenueCanceled: (summary.summaryRevenueCanceled).toFixed(),
                cashShiftOpen: (summary.cashShiftOpen).toFixed(),
                cashShiftClose: (summary.cashShiftClose).toFixed()
            });

            if (summary.saleFareItemDetails) {
                data.saleFareItemDetails = summary.saleFareItemDetails;
            }

            if (summary.summaryPaymentInstrumentItemDetails) {
                data.summaryPaymentInstrumentItemDetails = summary.summaryPaymentInstrumentItemDetails;
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    taskInformation = async (task) => {
        try {
            return {
                taskExecutionId: moment.utc().format('X'),
                taskId: task.id,
                taskEventId: moment.utc().format('X'),
                taskType: task.type
            };
        } catch (err) {
            log.error(err);
        }
    }

    taskEventInformation = async (penalty) => {
        try {
            return {
                passed: false,
                description: 'Inspector Comment',
                eventDetails: {
                    mobileTicketInspection: {
                        ticketNumber: penalty.ticketNumber
                    }
                },
                penaltyDetails: {
                    penaltyId: penalty.penaltyId,
                    riderId: penalty.riderId,
                    riderAccountId: penalty.riderAccountId,
                    riderName: penalty.riderName,
                    riderAddress: penalty.riderAddress,
                    riderEmail: penalty.riderEmail,
                    penaltyReasonId: penalty.penaltyReasonId,
                    penaltyProductId: penalty.penaltyProductId,
                    penaltyAmount: penalty.penaltyAmount,
                    riderComment: 'Rider Comment'
                }
            };
        } catch (err) {
            log.error(err);
        }
    }

    ticketSnapshot = async (ticket) => {
        try {
            let data = {
                ticketIssueTimestamp: moment.utc(ticket.ticketIssueTimestamp).toISOString(),
                fareItemType: ticket.fareItemType,
                issuingDeviceID: ticket.issuingDeviceId,
                issuingDeviceType: ticket.issuingDeviceType,
                ticketExpiryTimestamp: moment.utc(ticket.ticketExpiryTimestamp).toISOString(),
                ticketType: ticket.ticketType,
                passengerRiderTypeExternalIDFirst: ticket.passengerRiderTypeExternalIdFirst,
                noOfPassengersFirst: ticket.noOfPassengersFirst,
                fareItemExternalID: ticket.fareItemExternalId,
                fareItemIssuedNumber: ticket.fareItemIssuedNumber,
                allowedStagesOrZonesNumber: ticket.allowedStagesOrZonesNumber,
                routeTypeOrServiceTypeExternalID: ticket.routeTypeOrServiceTypeExternalId,
                routeTypeOrServiceTypeName: ticket.routeTypeOrServiceTypeName
            };

            if (ticket.issuedBoardingStopCode) {
                data.issuedBoardingStopCode = ticket.issuedBoardingStopCode;
            }
            if (ticket.issuedAlightingStopCode) {
                data.issuedAlightingStopCode = ticket.issuedAlightingStopCode;
            }
            if (ticket.issuedBoardingStationCode) {
                data.issuedBoardingStationCode = ticket.issuedBoardingStationCode;
            }
            if (ticket.issuedAlightingStationCode) {
                data.issuedAlightingStationCode = ticket.issuedAlightingStationCode;
            }

            if (ticket.ticketSerialNumber) {
                data.ticketSerialNumber = ticket.ticketSerialNumber;
            }

            if (ticket.issuedFormatType) {
                data.issuedFormatType = ticket.issuedFormatType;
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    cardReference = async (card) => {
        try {
            return {
                cardID: card.cardUid,
                cardPrintedID: card.cardPrintedId,
                cardType: card.cardType,
                cardTypeShortNumber: card.cardTypeShortNumber,
                cardVersion: card.cardVersion,
                cardVersionShortNumber: card.cardVersionShortNumber,
                physicalCardType: card.physicalCardType,
                cardIteration: card.cardIteration,
                issuerID: card.issuerId,
                cardTransactionCounter: card.transactionCounter
            };
        } catch (err) {
            log.error(err);
        }
    }

    cardSnapshot = async (card) => {
        try {
            let data = {
                timestamp: moment.utc(card.timestamp).toISOString(),
                cardTypeShortNumber: card.cardTypeShortNumber,
                cardVersionShortNumber: card.cardVersionShortNumber,
                cardIteration: card.cardIteration,
                currencyCode: card.currencyCode,
                preferredLanguage: card.preferredLanguage,
                riderType: card.riderTypeExternalId,
                storedValue: card.storedValue,
                refundableDeposit: card.refundableDeposit,
                cardExpirationTimestamp: moment.utc(card.cardExpirationTimestamp).toISOString(),
                issuerID: card.issuerId,
                counters: {
                    alic: card.alic,
                    alwc: card.alwc,
                    transactionCounter: card.transactionCounter
                },
                readOnly: {
                    cardID: card.cardUid,
                    cardType: card.cardType,
                    cardExpirationTimestamp: moment.utc(card.cardExpirationTimestamp).toISOString()
                },
                blockStatus: {
                    status: card.blockStatus,
                    cardBlockUnblockTimestamp: moment.utc(card.blockTimestamp).toISOString()
                },
                contracts: {}
            };

            if (card.contracts) {
                data.contracts = {
                    contract: []
                };
                for (let i=0; i<card.contracts.length; i++) {
                    let contractType;
                    switch (card.contracts[i].contractCategory) {
                        case constantsXml.contractType.ePurse:
                        case constantsXml.smartCardContractType.ePurse:
                            contractType = constantsXml.contractType.ePurse;
                        break;
                        case constantsXml.contractType.periodPass:
                        case constantsXml.smartCardContractType.periodPass:
                            contractType = constantsXml.contractType.periodPass;
                        break;
                        case constantsXml.contractType.storedRides:
                        case constantsXml.smartCardContractType.storedRides:
                            contractType = constantsXml.contractType.storedRides;
                        break;
                    }
                    data.contracts.contract.push({
                        contractType: contractType,
                        productID: card.contracts[i].contractId,
                        contractID: card.contracts[i].contractId,
                        instanceID: card.contracts[i].instanceId,
                        contractStatus: card.contracts[i].contractStatus,
                        contractStartTimestamp: moment.utc(card.contracts[i].contractStartTimestamp).toISOString(),
                        contractExpirationTimestamp: moment.utc(card.contracts[i].contractExpirationTimestamp).toISOString(),
                        //contractStatusChangeTimestamp: moment.utc(card.contracts[i].contractStateChangeTimestamp).toISOString(),
                        contractValue: card.contracts[i].contractValue
                    });
                }
            }

            if (card.cardUidOld) {
                data.readOnly.oldCardID = card.cardUidOld;
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    cardOperation = async (card) => {
        try {
            let data = {};

            if (card.issuing) {
                data.issuing = {
                    issueType: card.issuing
                };
            }

            if (card.addContract) {
                data.addContract = {
                    contractType: card.addContract.contractType,
                    productID: card.addContract.productId,
                    contractID: card.addContract.contractId,
                    instanceID: card.addContract.instanceId,
                    contractStatus: constantsXml.contractStatusType.active,
                    contractStartTimestamp: moment.utc(card.addContract.contractStartTimestamp).toISOString(),
                    contractExpirationTimestamp: moment.utc(card.addContract.contractExpirationTimestamp).toISOString(),
                    contractValue: card.addContract.contractValue
                };
            }

            if (card.modifyContract) {
                data.modifyContract = {
                    contractType: card.modifyContract.contractType,
                    productID: card.modifyContract.productId,
                    contractID: card.modifyContract.contractId,
                    instanceID: card.modifyContract.instanceId,
                    previousContractStatus: card.modifyContract.previousContractStatus,
                    contractStatus: constantsXml.contractStatusType.active,
                    previousContractStartTimestamp: moment.utc(card.modifyContract.previousContractStartTimestamp).toISOString(),
                    contractStartTimestamp: moment.utc(card.modifyContract.contractStartTimestamp).toISOString(),
                    previousContractExpirationTimestamp: moment.utc(card.modifyContract.previousContractExpirationTimestamp).toISOString(),
                    contractExpirationTimestamp: moment.utc(card.modifyContract.contractExpirationTimestamp).toISOString(),
                    previousContractValue: card.modifyContract.previousContractValue,
                    contractValue: card.modifyContract.contractValue
                };
            }

            if (card.removeContract) {
                data.removeContract = {
                    contractType: card.removeContract.contractType,
                    productID: card.removeContract.productId,
                    contractID: card.removeContract.contractId,
                    instanceID: card.removeContract.instanceId
                };
            }

            if (card.addEpurseContract) {
                data.addEpurseContract = {
                    productID: card.addEpurseContract.productId,
                    contractID: card.addEpurseContract.contractId,
                    instanceID: card.addEpurseContract.instanceId,
                    extraData: card.addEpurseContract.extraData
                };
            }

            if (card.creditEpurse) {
                data.creditEpurse = {
                    newEpurseValue: card.creditEpurse.newEpurseValue,
                    previousEpurseValue: card.creditEpurse.previousEpurseValue
                };
            }

            if (card.addPeriodPass) {
                data.addPeriodPass = {
                    productID: card.addPeriodPass.productId,
                    contractID: card.addPeriodPass.contractId,
                    instanceID: card.addPeriodPass.instanceId,
                    activateOnFirstUsage: card.addPeriodPass.activateOnFirstUsage
                };
            }

            if (card.addStoredRides) {
                data.addStoredRides = {
                    productID: card.addStoredRides.productId,
                    contractID: card.addStoredRides.contractId,
                    instanceID: card.addStoredRides.instanceId,
                    salesAmount: card.addStoredRides.contractValue,
                    extraData: card.addStoredRides.extraData
                };
            }

            if (card.changeRiderType) {
                data.changeRiderType = {
                    newRiderType: card.changeRiderType.newRiderType,
                    previousRiderType: card.changeRiderType.previousRiderType,
                    newRiderTypeExpirationTimestamp: moment.utc(card.changeRiderType.newRiderTypeExpirationTimestamp).toISOString()
                };
            }

            if (card.cardBlock) {
                data.cardBlock = {};
            }

            if (card.cardUnblock) {
                data.cardUnblock = {};
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    actionResponse = async (action) => {
        try {
            return {
                sequenceNumber: action.sequenceNumber,
                name: action.name,
                success: action.success,
                keptInQueue: action.keptInQueue,
                alic: action.alic,
                alwc: action.alwc
            };
        } catch (err) {
            log.error(err);
        }
    }

    penaltyIssue = async (parameters) => {
        try {
            return {
                avlInformation: await this.avlInformation(parameters.avl),
                fareModelInformation: await this.fareModelInformation(parameters.fare),
                taskInformation: await this.taskInformation(parameters.task),
                taskEventInformation: await this.taskEventInformation(parameters.penalty)
            };
        } catch (err) {
            log.error(err);
        }
    }

    cashInformation = async (cash) => {
        try {
            return {
                cashOperationType: cash.cashOperationType,
                cashActivityType: cash.cashActivityType,
                previousBalance: (cash.previousBalance).toFixed(),
                newBalance: (cash.newBalance).toFixed()
            };
        } catch (err) {
            log.error(err);
        }
    }

    cashCollectionInformation = async (collection) => {
        try {
            return {
                cashCollectionSessionId: collection.cashCollectionSessionId,
                cashCollectionEventId: collection.cashCollectionEventId,
                collectedByUserType: collection.collectedByUserType,
                collectedByEmployeeRef: collection.collectedByEmployeeRef,
                collectedByEmployeeRoleNumber: collection.collectedByEmployeeRoleNumber,
                collectedByEmployeeRoleName: collection.collectedByEmployeeRoleName
            };
        } catch (err) {
            log.error(err);
        }
    }

    cashContainerStatusInformation = async (container) => {
        try {
            return {
                previousCashContainerOperationalStatus: container.previousOperationalStatus,
                newCashContainerOperationalStatus: container.newOperationalStatus,
                previousCashContainerLevelStatusStatus: container.previousLevelStatusStatus,
                newCashContainerLevelStatus: container.newLevelStatus,
                previousCashContainerBlockStatusStatus: container.previousBlockStatusStatus,
                newCashContainerBlockStatus: container.newBlockStatus
            };
        } catch (err) {
            log.error(err);
        }
    }

    bookingInformation = async (booking) => {
        try {
            return {
                bookingReference: booking.bookingReference,
                reservationSeat: booking.reservationSeat,
                eTicketReference: booking.eTicketReference
            };
        } catch (err) {
            log.error(err);
        }
    }

    boardingInformation = async (boarding) => {
        try {
            let data = {
                boardingActivity: boarding.boardingActivity,
                issuedBoardingStopCode: boarding.issuedBoardingStopCode,
                issuedAligthingStopCode: boarding.issuedAligthingStopCode,
                issuedBoardingZoneCode: boarding.issuedBoardingZoneCode,
                issuedAligthingZoneCode: boarding.issuedAligthingZoneCode,
                tripDistanceTraveled: boarding.tripDistanceTraveled,
                tripStagesOrZonesTraveled: boarding.tripStagesOrZonesTraveled
            };

            if (boarding.issuedBoardingStationCode) {
                data.issuedBoardingStationCode = boarding.issuedBoardingStationCode;
            }
            if (boarding.issuedAligthingStationCode) {
                data.issuedAlightingStationCode = boarding.issuedAligthingStationCode;
            }
            if (boarding.actualBoardingStopCode) {
                data.actualBoardingStopCode = boarding.actualBoardingStopCode;
            }
            if (boarding.actualAligthingStopCode) {
                data.actualAligthingStopCode = boarding.actualAligthingStopCode;
            }
            if (boarding.actualBoardingStationCode) {
                data.actualBoardingStationCode = boarding.actualBoardingStationCode;
            }
            if (boarding.actualAligthingStationCode) {
                data.actualAlightingStationCode = boarding.actualAligthingStationCode;
            }
            if (boarding.boardingTimestamp) {
                data.boardingTimestamp = moment.utc(boarding.boardingTimestamp).toISOString();
            }
            if (boarding.alightingTimestamp) {
                data.alightingTimestamp = moment.utc(boarding.alightingTimestamp).toISOString();
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

    taxInvoiceInformation = async (invoice) => {
        try {
            return {
                invoiceIdNumber: invoice.invoiceIdNumber,
                invoiceExternalReferenceCode: invoice.invoiceExternalReferenceCode,
                taxInvoiceQrCode: invoice.taxInvoiceQrCode
            };
        } catch (err) {
            log.error(err);
        }
    }

    salesOrderInformation = async (order) => {
        try {
            return {
                salesOrderIdNumber: order.salesOrderIdNumber,
                salesOrderExternalReferenceCode: order.salesOrderExternalReferenceCode
            };
        } catch (err) {
            log.error(err);
        }
    }

    customTransactionParameters = async (custom) => {
        try {
            let data = {
                customTransactionParameter: []
            };

            for (let i=0; i<custom.parameters.length; i++) {
                data.customTransactionParameter.push({
                    customTransactionParameterCode: custom.parameters[i].code,
                    customTransactionParameterValue: custom.parameters[i].value
                });
            }

            return data;
        } catch (err) {
            log.error(err);
        }
    }

}

module.exports = PosTransactionServ;
