sambat.py 6.16 KB
import transaction
from pyramid.view import view_config
from deform import ValidationFailure
from opensipkd.string import FixLength
from opensipkd.iso8583.bjb.pbb.structure import INVOICE_PROFILE
from opensipkd.iso8583.bjb.pbb.agratek.models import (
    Rpc,
    Log,
    )
from iso8583_web.scripts.tools import iso_to_dict
from iso8583_web.read_conf import web_path_conf
from iso8583_web.scripts.logger import (
    log_web_info,
    log_web_error,
    )
from . import (
    WebJob as BaseWebJob,
    View as BaseView,
    )
from pyramid_linkaja.exceptions import (
    InvoiceIdError,
    NeedPostError,
    InternalError,
    TrxTypeError,
    HostError,
    AlreadyPaidError,
    TimeoutError,
    BaseError,
    AmountError,
    BillRefNotFound,
    PaymentNotFound,
    LinkError,
    )
from pyramid_linkaja.responses import (
    InquiryResponse,
    PaymentResponse,
    get_trx_date,
    get_method,
    get_template_response,
    is_inquiry,
    is_payment,
    is_reversal,
    )
from pyramid_linkaja.decorator import csv_method
from pyramid_linkaja.structure import RENDERER
from pyramid_linkaja.form import get_form
from . import (
    get_inquiry,
    get_payment,
    pyramid_init as base_pyramid_init,
    )


ROUTE = 'linkaja-sambat'

conf = dict()


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


class WebJob(BaseWebJob):
    def timeout_error(self):  # override
        return TimeoutError()


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_web_job_cls(self):  # Override
        return WebJob

    def not_found_error(self, hostname):  # Override
        return HostError(hostname)

    def not_running_error(self, hostname):  # Override
        msg = f'Host {hostname} belum terhubung'
        return InternalError(msg, 'Sedang offline')

    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()
        web_conf = self.get_web_conf()
        row = Rpc(
            ip=self.request.client_addr,
            conf_name=web_conf['name'],
            merchant=data['merchant'],
            terminal=data['terminal'],
            trx_type=data['trx_type'],
            msisdn=data['msisdn'],
            acc_no=data['acc_no'],
            stan=iso_req.get_stan())
        row.trx_date = get_trx_date(data),
        if data.get('msg'):
            row.msg = data['msg']
        if data.get('amount'):
            row.amount = int(data['amount'])
        if not is_inquiry(data):
            row.inquiry_id = inq and inq.id or pay.inquiry_id
            row.ntb = data['trx_id']
        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_response(self, data):
        p, inq, pay = self.prepare_response(data)
        return self.after_send_iso(data, inq, pay, row, iso_resp)  #FIXME

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


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


# Dipanggil forwarder.py
def pyramid_init(config):
    base_pyramid_init(config, conf, ROUTE)