pbb.py 5.61 KB
import transaction
from ISO8583.ISOErrors import BitNotSet
from opensipkd.string import FixLength
from opensipkd.iso8583.bjb.pbb.structure import INVOICE_PROFILE
from opensipkd.iso8583.bjb.pbb.agratek.models import Log
from iso8583_web.scripts.tools import iso_to_dict
from pyramid_linkaja.exceptions import (
    InvoiceIdError,
    TrxTypeError,
    AlreadyPaidError,
    BaseError,
    AmountError,
    BillRefNotFound,
    PaymentNotFound,
    LinkError,
    )
from pyramid_linkaja.responses import (
    InquiryResponse,
    PaymentResponse,
    get_method,
    get_template_response,
    is_inquiry,
    is_payment,
    is_reversal,
    )
from pyramid_linkaja.decorator import csv_method
from . import View as BaseView
from . import pyramid_init as base_pyramid_init


ROUTE = 'linkaja-pbb'

conf = dict()


def get_db_session():
    return conf['db_session']


def profile2name(profile):
    msg = [profile['Nama'].strip()]
    fields = [('Tagihan', 'Pok'), ('Denda', 'Den'), ('Discount', 'Disk')]
    for field, label in fields:
        s = profile[field].strip().lstrip('0')
        if s:
            msg.append(f'{label} {s}')
    fields = ['Nama Kelurahan', 'Nama Kecamatan', 'Lokasi']
    for field in fields:
        s = profile[field].strip()
        if s:
            msg.append(s)
    return ', '.join(msg)


def get_ok_notify(data):
    for key in conf['notification_message']:
        if data['acc_no'].find(key) == 0:
            return conf['notification_message'][key]
    return ''


class View(BaseView):
    def get_db_session(self):  # Override
        return get_db_session()

    def create_iso_log(self, iso, rpc):
        conf = self.get_iso_conf()
        iso_log = Log(
            mti=iso.getMTI(),
            rpc_id=rpc.id,
            ip=conf['ip'],
            conf_name=conf['name'])
        for bit in iso.get_bit_definition():
            try:
                value = iso.getBit(bit)
            except BitNotSet:
                continue
            field = 'bit_{}'.format(str(bit).zfill(3))
            setattr(iso_log, field, value)
        try:
            data = iso.getBit(62)
            profile = FixLength(INVOICE_PROFILE)
            profile.set_raw(data)
            iso_log.bit_062_data = profile.to_dict()
        except BitNotSet:
            pass
        return iso_log

    def before_send_iso(self, data, inq, pay, iso_req):
        DBSession = get_db_session()
        row = self.create_db_log(data, inq, pay)
        row.stan = iso_req.get_stan()
        with transaction.manager:
            DBSession.add(row)
            DBSession.flush()
            DBSession.expunge_all()  # Agar dapat row.id
            iso_log = self.create_iso_log(iso_req, row)
            DBSession.add(iso_log)
        return row

    def after_send_iso(self, data, inq, pay, row, iso_resp):
        DBSession = get_db_session()
        iso_log = self.create_iso_log(iso_resp, row)
        iso_data = iso_to_dict(iso_resp)
        web_data = get_template_response(data)
        if iso_data[39] == '00':
            web_data['Response Code'] = '00'
            web_data['Notification Message'] = get_ok_notify(data)
            if is_inquiry(data):
                web_data['Bill Ref'] = str(row.id)
            if iso_data.get(62):
                profile = FixLength(INVOICE_PROFILE)
                profile.set_raw(iso_data[62])
                iso_log.bit_062_data = profile.to_dict()
                web_data['Biller Name'] = row.biller_name = \
                    profile2name(profile)
            web_data['Bill Amount'] = iso_data[4].lstrip('0')
            if iso_data.get(47):
                web_data['Transaction ID'] = row.ntp = iso_data[47]  # NTP
            err = None
        elif iso_data[39] in ['33', '55']:
            err = InvoiceIdError()
        elif iso_data[39] == '54':
            if is_reversal(data):
                err = PaymentNotFound()
            else:
                err = AlreadyPaidError()
        elif iso_data[39] == '51':
            err = AmountError()
        elif iso_data[39] == '91':
            err = LinkError()
        else:
            err = BaseError()
        if err:
            web_data.from_err(err)
            row.resp_msg = web_data['Notification Message']
        self.log_send(web_data.values)
        row.resp_code = web_data['Response Code']
        row.resp_msg = web_data['Notification Message']
        with transaction.manager:
            DBSession.add(row)
            DBSession.add(iso_log)
        return web_data

    def get_invoice_id(self, data):  # Override
        s = data['acc_no']
        if len(s) == 18:
            s += data['msg']
        return s

    def get_invoice_id_from_inquiry(self, inq):
        s = inq.acc_no
        if len(s) == 18:
            s += inq.msg
        return s

    def get_response(self, data):  # Override
        p, inq, pay = self.prepare_response(data)
        conn = self.get_connection()
        method = get_method(data)
        iso_func = getattr(conn.job, method)
        iso_req = iso_func(p)
        row = self.before_send_iso(data, inq, pay, iso_req)
        iso_resp = self.web_job(conn, iso_req)
        return self.after_send_iso(data, inq, pay, row, iso_resp)

    @csv_method(route_name=ROUTE)
    def view(self):
        return super().view()


# Dipanggil read_conf.py
def init(cfg):
    conf.update(cfg)


def str2dict(s):
    r = dict()
    for token in s.split('\n'):
        s = token.strip()
        if not s:
            continue
        key, value = s.split(':')
        r[key] = value
    return r


# Dipanggil forwarder.py
def pyramid_init(config):
    base_pyramid_init(config, conf, ROUTE)
    conf['notification_message'] = str2dict(conf['notification_message'])