partner-trugee.js 6.92 KB
var http = require('http');
var url = require('url');
var math = require('mathjs');
var xml = require('xml');
var xml2js = require('xml2js').parseString;
var strftime = require('strftime');
var xor = require('base64-xor');
var request = require('request');
var winston = require('winston');

var config;
var callbackReport;
var aaa;
var logger;

var max_retry = 2;
var sleep_before_retry = 2000;

var trx_balances = {};
var trx_prices = {};

function calculateSignature(password, msisdn, timestamp) {
    var a = timestamp + msisdn.substr(msisdn.length - 4);
    var b = msisdn.substr(msisdn.length - 4).split('').reverse().join('') + password;

    return xor.encode(a,b);
}

function createPayload(task) {
    var timestamp = strftime('%H%M%S');

    var payload = {
        pulsamatic: [
            {command: 'TOPUP'},
            {vtype: task['remoteProduct']},
            {userid: config.h2h_out.userid},
            {time: timestamp},
            {msisdn: task['destination']},
            {trxid: task['requestId']},
            {sign: calculateSignature(config.h2h_out.password, task['destination'], timestamp)}
        ]
    };

    //console.log(payload);
    return "<?xml version=\"1.0\" ?>\n" + xml(payload);
}

function topupRequest(task, retry) {

    aaa.insertTaskToMongoDb(task);

    var payload_xml = createPayload(task);
    var partner = url.parse(config.h2h_out.partner);

    var request_options = {
        host: partner.hostname,
        path: partner.path,
        port: partner.port,
        method: "POST",
        headers: {
            'Content-Type': 'text/xml',
            'Content-Length': Buffer.byteLength(payload_xml)
        }
    };

    var buffer = "";

    logger.info('Requesting to partner', {request_options: request_options});

    var req = http.request(request_options, function( res )    {

        logger.info('Status code: ' + res.statusCode );
        var buffer = "";
        res.on( "data", function( data ) { buffer = buffer + data; } );
        res.on( "end", function( data ) {
            directResponseHandler(buffer, task['requestId']);
        });

    });

    req.on('error', function(e) {
        logger.warn('problem with request: ' + e.message);
        callbackReport(task['requestId'], '40', e.message);
    });

    logger.verbose('Sending payload to partner', {payload: payload_xml});
    req.write( payload_xml );
    req.end();
}

function directResponseHandler(body, request_id) {
    logger.info('Got direct response');

    xml2js(body, function (err, result) {
        if (err) {

            if (body == 'Error: MAINTENANCE SYSTEM') {
                callbackReport(request_id, '91', body);
            } else {
                logger.warn('Error parsing xml', {err: err, body: body});
                callbackReport(request_id, '40', 'Error parsing xml. ' + err);
            }

            return;
        }

        logger.info('Direct response parsed', {result: result});

        var response_code = '68';

        //var request_id = result.pulsamatic.partner_trxid[0].trim();
        var message = getMessageFromXmlResponse(result);
        if (!message) {
            message = body;
        }

        var status = getStatusFromXmlResponse(result);
        if (!status) {
            status = 'UNKNOWN';
        }

        if (status === 'failed') {
            response_code = '40';

            var new_response_code = responseCodeFromMessage(message);
            if (new_response_code) {
                response_code = new_response_code;
            }

        }

        callbackReport(request_id, response_code, message);
    });
}

function getMessageFromXmlResponse(response) {
    var message = null;
    try {
        message = response.pulsamatic.message[0].trim();
    }
    catch(e) {
        logger.warn('Undefined message from response pulsamatic', {response: response});
    }
    return message;
}

function getStatusFromXmlResponse(response) {
    var status = null;
    try {
        status = response.pulsamatic.result[0].trim();
    }
    catch(e) {
        logger.warn('Undefined status from response', {response: response});
    }
    return status;
}


function responseCodeFromMessage(message) {
    if (message.indexOf('Jenis produk tidak cocok') >= 0) {
        return '14';
    } else if (message.indexOf('GAGAL. Nomor telp salah.') >= 0) {
        return '14';
    } else if (message.indexOf('GAGAL. Nomor telpon tidak valid') >= 0) {
        return '14';
    } else if (message.indexOf('GAGAL. MSISDN tidak ditemukan') >= 0) {
        return '14';
    } else if (message.indexOf('GAGAL. Nomor MSISDN sudah tidak aktif') >= 0) {
        return '14';
    } else if (message.indexOf('GAGAL. Jenis produk ini sedang gangguan.') >= 0) {
        return '13';
    }
    return;
}

function createServer() {

    var httpServer = http.createServer(function(req, res) {
        //console.log('Got request from partner ("' + req.url + '")');
        var sn;

        res.end('OK');

        var qs = url.parse(req.url, true).query;
        logger.info('Reverse Report', {qs: qs});

        var response_code = '68';
        var request_id = qs.pid;
        var message = qs.msg;

        if (qs.code == 2) {
            // gagal
            response_code = '40';
        } else if (qs.code == 3) {
            // refund
            response_code = '40';
        } else if (qs.code == 4) {

            response_code = '00';
            sn = qs.sn;
            if (sn && typeof sn === 'string') {
                sn = sn.toUpperCase().replace(/[^A-Z0-9\/]/g, '-').replace(/-+/g, '-').replace(/-+\//g, '/').replace(/^-+/, '').replace(/-+$/, '');
            }

            message = 'SN=' + sn + '; ' + message;
        }

        if (response_code == '40') {
            var new_response_code = responseCodeFromMessage(message);
            if (new_response_code) {
                response_code = new_response_code;
            }
        }

        callbackReport(request_id, response_code, message);
    });

    httpServer.listen(config.h2h_out.listen_port, function() {
        logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
    });
}

function start(options) {
    if (!options) {
        console.log('Undefined options, terminating....');
        process.exit(1);
    }

    if (options.config) {
        config = options.config;
    } else {
        console.log('Undefined options.config, terminating....')
        process.exit(1);
    }

    if (options.aaa) {
        aaa = options.aaa;
        callbackReport = options.aaa.callbackReportWithPushToMongoDb;
    } else {
        console.log('Undefined options.aaa, terminating....')
        process.exit(1);
    }

    if (options && options.logger) {
        logger = options.logger;
    } else {
        logger = new winston.Logger({
            transports: [
              new (winston.transports.Console)()
            ]
        });
    }

    createServer();
}

exports.start = start;
exports.topupRequest = topupRequest;
exports.calculateSignature = calculateSignature;