transaction.py 7.56 KB
from datetime import datetime
from ISO8583.ISOErrors import BitNotSet
from opensipkd.string import (
    DateTimeVar,
    DateVar, TimeVar,
    exception_message,

    )
from opensipkd.iso8583.network import Doc as BaseTransaction
from .structure import (
    TRANSACTION_BITS,
    INQUIRY_CODE,
    PAYMENT_CODE,
    REPRINT1_CODE,
    REPRINT2_CODE,
    RC_OK,
    ERR_TRANSACTION_DATE,
    ERR_SETTLEMENT_DATE,
    ERR_OTHER,
    ERR_TRANSACTION_DATETIME,

    RC_INVALID_NUMBER,
    ERR_SETTLEMENT_DATE,
    ERR_TRANSACTION_DATETIME,
    ERR_TRANSACTION_DATE,
    ERR_INVALID_BANK,
    ERR_INVALID_NUMBER,
    ERR_TRANSACTION_TIME,
    )


from opensipkd.waktu import create_datetime
from iso8583_web.scripts.forwarder import Log

CHANNEL_NAMES = {
    'INDOMARET': 1,
    'ALFAMART': 2,
    'ALFAMIDI': 3,
    'TOKOPEDIA': 4,
    'KASPRO': 5,
    'BUKALAPAK': 6,
    'VALUESTREAM': 9,
    }


class Transaction(BaseTransaction, Log):
    def __init__(self, *args, **kwargs):
        self.conf = kwargs["conf"]
        self.mod_conf = dict()
        for key in self.conf['module_conf']:
            if key.find('samsat_banten_') < 0:
                continue
            name = key[14:]
            self.mod_conf[name] = self.conf['module_conf'][key]

        del kwargs["conf"]
        BaseTransaction.__init__(self, *args, **kwargs)
        self.transmission_datetime = DateTimeVar()
        self.transaction_date = DateVar()
        self.settlement_date = DateVar()
        self.transaction_time = TimeVar()
        self.transaction_datetime = DateTimeVar()

    # Override
    def get_bit_definition(self):
        return TRANSACTION_BITS

    # Override
    def get_func_name(self):
        return self.is_sign_on_request() or self.is_sign_off_request() or \
               self.is_echo_request() or \
               self.is_inquiry_request() or self.is_payment_request() or \
               self.is_reversal()

    # Override
    def process(self):
        func_name = self.from_iso.get_func_name()
        if func_name:
            func = getattr(self, func_name)
            func()
        else:
            self.ack_function_not_found()

    # Override
    def set_response(self):
        if self.from_iso.is_network_request():
            BaseTransaction.set_response(self)
        elif self.from_iso.is_transaction():
            self.set_transaction_response()
        elif self.from_iso.is_reversal():
            self.set_reversal_response()

    # Override
    def setIsoContent(self, raw):
        BaseTransaction.setIsoContent(self, raw)
        self.raw = raw

    def is_transaction_response(self):
        return self.getMTI() == '0210'

    def is_response(self):
        return BaseTransaction.is_response(self) or self.is_transaction_response()

    def is_transaction(self):
        return self.getMTI() in ['0200', '0210']

    def get_transaction_code(self):
        return self.getBit(3)

    def is_inquiry_response(self):
        return self.getMTI() == '0210' and \
            self.get_transaction_code() == INQUIRY_CODE

    def is_inquiry_request(self):
        if not self.is_transaction():
            return
        code = self.get_transaction_code()
        return code == INQUIRY_CODE and 'inquiry_response'

    def is_payment_request(self):
        if not self.is_transaction():
            return
        code = self.get_transaction_code()
        return code in (PAYMENT_CODE, REPRINT1_CODE, REPRINT2_CODE) and \
            'payment_response'

    def is_reprint(self):
        return self.get_transaction_code() in (REPRINT1_CODE, REPRINT2_CODE)

    def set_transaction_response(self):
        kini = datetime.now()
        self.setBit(12, kini.strftime('%H%M%S'))
        self.setBit(13, kini.strftime('%m%d'))
        self.setMTI('0210')
        # Sesuai kolom yang berisi E (Equal) pada dokumentasi
        self.copy([2, 3, 11, 12, 13, 15, 18, 22, 32, 33, 35, 37, 41, 43, 49,
                   61, 62])

    def get_transmission_datetime(self):
        raw = self.get_value(7)
        self.transmission_datetime.set_raw(raw)
        # without time zone
        t = self.transmission_datetime.get_value()
        # with time zone
        t = create_datetime(t.year, t.month, t.day, t.hour, t.minute, t.second)
        return t

    def get_transaction_date(self):
        raw = self.get_value(13)
        self.transaction_date.set_raw(raw)
        try:
            return self.transaction_date.get_value()
        except ValueError:
            msg = ERR_TRANSACTION_DATE.format(d=raw)
            self.ack_other(msg)

    def get_settlement_date(self):
        raw = self.get_value(15)
        self.settlement_date.set_raw(raw)
        try:
            return self.settlement_date.get_value()
        except ValueError:
            msg = ERR_SETTLEMENT_DATE.format(d=raw)
            self.ack_other(msg)

    def get_transaction_date_raw(self):
        return self.get_value(13)

    def get_transaction_datetime_raw(self):
            return self.get_transaction_date_raw() + self.get_transaction_time_raw()

    def get_transaction_datetime(self):
        raw = self.get_transaction_datetime_raw()
        self.transaction_datetime.set_raw(raw)
        try:
            return self.transaction_datetime.get_value()
        except ValueError:
            self.ack_transaction_datetime()

    def get_transaction_time_raw(self):
        return self.get_value(12)

    def get_transaction_time(self):
        raw = self.get_transaction_time_raw()
        self.transaction_time.set_raw(raw)
        try:
            return self.transaction_time.get_value()
        except ValueError:
            self.ack_transaction_time()

    def ack_transaction_datetime(self):
        raw = self.get_transaction_datetime_raw()
        msg = ERR_TRANSACTION_DATETIME.format(raw=[raw])
        self.ack_other(msg)

    def ack_transaction_time(self):
        raw = self.get_transaction_time_raw()
        msg = ERR_TRANSACTION_TIME.format(raw=[raw])
        self.ack_other(msg)

    def get_bit_invoice_profile(self):
        return 61

    def get_invoice_id_raw(self):
        return self.get_value(self.get_bit_invoice_profile())

    def set_invoice_profile(self, raw):
        self.setBit(self.get_bit_invoice_profile(), raw)

    def get_ntb(self):
        return self.get_value(37)

    def set_ntb(self, ntb):
        self.setBit(37, ntb)

    def set_ntp(self, ntp):
        self.setBit(47, ntp)

    def get_amount(self):
        return int(self.get_value(4))

    def get_channel_id(self):
        return self.get_value(18)

    def get_channel_name(self):
        try:
            s = self.get_value(43)
        except BitNotSet:
            return ''
        t = s.split()
        return t and t[0] or ''

    def get_channel_name_to_id(self):
        name = self.get_channel_name()
        if name in CHANNEL_NAMES:
            s = CHANNEL_NAMES[name]
            return str(s).zfill(3)
        return '000'

    def get_bank_ip(self):
        return self.conf['ip']

    def get_bank_id(self):
        # if 'id' in self.conf:
        #     return self.conf['id'] # bjb
        return int(self.from_iso.get_value(32))

    def is_reversal(self):
        s = self.getMTI()
        return s[:2] == '04' and 'reversal_response'

    def set_reversal_response(self):
        s = self.from_iso.getMTI()
        mti = s[:2] + '1' + s[3:] # 0400 -> 0410, 0401 -> 0411
        self.setMTI(mti)
        self.copy(from_iso=self.from_iso)

    def ack_other(self, msg=ERR_OTHER):
        self.setBit(62, msg)
        BaseTransaction.ack_other(self, msg)

    def ack_timeout(self, msg='Biller Timeout'):
        self.ack(68, msg)

    def set_transaction_code(self, code):
        self.setBit(3, code)