partner-otomax.js 6.83 KB
"use strict";

var request = require('request');
var crypto = require('crypto');
var url = require('url');
var http = require('http');

var resendDelay = require('sate24/resend-delay');
var taskHistory = require('sate24/task-history');
var AntiSameDayDupe = require('sate24/anti-same-day-dupe-oo');
var antiSameDayDupe;

var config;
var aaa;
var logger;


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;
    } else {
        console.log('Undefined options.aaa, terminating....')
        process.exit(1);
    }

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

    resendDelay.init({
        config: config,
        topupRequest: checkStatus,
        logger: logger
    });

    taskHistory.init(options);
    antiSameDayDupe.init(options);

    createReverseHttpServer();
}

function callbackReport(requestId, rc, message) {
    if (rc != '68') {
        resendDelay.cancel(requestId);
    } else {
        taskHistory.get(requestId, function(err, archivedTask) {
            if (archivedTask) {
                resendDelay.register(archivedTask);
            } else {
                logger.warn('Can not find task from history', {request_id: requestId});
            }
        });
    }

    aaa.callbackReportWithPushToMongoDb(requestId, rc, message);
}

function topupRequest(task) {
    if (!aaa.isTodayTrx(task)) {
        logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan');
        callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan');
        resendDelay.cancel(task);
        return;
    }

    aaa.insertTaskToMongoDb(task);

    if (!antiSameDayDupe) {
        logger.info('Initializing antiSameDayDupe');
        antiSameDayDupe = new AntiSameDayDupe({
            config: config,
            logger: logger,
            keyPrefix: 'otomax.',
            redisClient: redisClient
        });
    }
    antiSameDayDupe.check(task, _topupRequest, onSameDayDupe, checkStatus);
}

function _topupRequest(task) {
    taskHistory.put(task, function() {
        requestToPartner(task);;
    });
}

function checkStatus(task) {
    logger.verbose('Going to request checkStatus', {task: task});
    taskHistory.put(task, function() {
        requestToPartner(task, true);
    });
}

function requestToPartner(task, pendingOnErrorConnect) {
    let requestOptions = createRequestOptions(task);

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

    request(requestOptions, function(error, response, body) {
        if (error) {
            let rc = '68';

            if (!pendingOnErrorConnect && (error.syscall == 'connect')) {
                rc = '91';
            }

            logger.warn('Error requesting to partner', {task: task, rc: rc, error: error});
            callbackReport(task.requestId, rc, 'Error requesting to partner. ' + error);
            return;
        }

        if (response.statusCode != 200) {
            logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode});
            callbackReport(task.requestId, '40', 'HTTP status code ' + response.statusCode);
            return;
        }

        logger.verbose('Got response from partner', {task: task, body: body});

        parseMessage(task, body);
    });
}

function getRequestIdFromTask(task) {
    if (typeof task == 'string') {
        return task;
    }

    try {
        let requestId = task.requestId;
        return requestId;
    }
    catch(e) {return};
}

function parseMessage(task, message) {
    let requestId = getRequestIdFromTask(task);

    if (!requestId) {
        logger.warn('Invalid requestId on parseMessage', {task: task, message: message});
        return;
    }

    let rc = '68';

    if (message.indexOf('SUKSES') >= 0) {
        rc = '00';
    }
    else if (message.indexOf('GAGAL. Nomor tujuan salah') >= 0) {
        rc = '14';
    }
    else if (message.indexOf('NO HP TIDAK TERDAFTAR ATAU BUKAN NOMOR PRA-BAYAR') >= 0) {
        rc = '14';
    }
    else if (message.indexOf('Gagal.') >= 0) {
        rc = '40';
    }
    else if (message.indexOf('GAGAL') >= 0) {
        rc = '40';
    }
    else if (message.indexOf('gagal, dibatalkan SILAHKAN DICOBA KEMBALI') >= 0) {
        rc = '40';
    }
    else if (message.indexOf('Invalid Signature') >= 0) {
        rc = '40';
    }

    if (rc == '00') {
        let sn = parseSn(message, config.h2h_out.sn_pattern);
        if (sn) {
            message = "SN=" + sn + ";" + message;
        }
    }

    callbackReport(requestId, rc, message);
}

function generateSign(userid, remoteProduct, destination, requestId, pin, password) {
    let plain = ["OtomaX", userid, remoteProduct, destination, requestId, pin, password].join("|");
    //let sha1 = crypto.createHash('sha1').update(plain).digest().toString('hex');
    //let buffer = new Buffer(sha1);
    let buffer = crypto.createHash('sha1').update(plain).digest();

    return buffer.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
}

function createRequestOptions(task) {
    return {
        url: config.h2h_out.partner,
        qs: {
            memberID: config.h2h_out.userid,
            product: task.remoteProduct,
            dest: task.destination,
            refID: task.requestId,
            sign: generateSign(
                config.h2h_out.userid,
                task.remoteProduct,
                task.destination,
                task.requestId,
                config.h2h_out.pin,
                config.h2h_out.password
            )
        }
    };
}

function onSameDayDupe(task) {
    callbackReport(task.requestId, '55', 'Transaksi duplikat dalam satu hari yang sama');
}

function reverseHttpServerServerHandler(request, response) {
    let qs = url.parse(request.url, true).query;
    logger.verbose('Hit on Reverse HTTP server', {url: request.url, qs: qs});

    parseMessage(qs.refid, qs.message);
}

function createReverseHttpServer() {
    var httpServer = http.createServer(reverseHttpServerServerHandler);

    httpServer.listen(config.h2h_out.listen_port, function() {
        logger.info('Reverse Report HTTP Server listen on %d', config.h2h_out.listen_port);
    });
}

function parseSn(message, pattern) {

    try {
        let sn_regex = new RegExp(pattern);
        let sn_match = message.match(sn_regex);

        return sn_match[1].trim();
    }
    catch(e) {
        return;
    }

}

exports.start = start;
exports.topupRequest = topupRequest;
exports.checkStatus = checkStatus;
exports.generateSign = generateSign;
exports.parseSn = parseSn;