__init__.py 9.16 KB
import transaction
import venusian
from ISO8583.ISOErrors import BitNotSet
from deform import (
    ValidationFailure,
)
from iso8583_web.scripts.logger import (
    log_web_info,
    log_web_debug)
from iso8583_web.scripts.views import WebJob
from opensipkd.string import (
    FixLength,
)
from pyramid.view import (
    notfound_view_config,
)

from .structure import INVOICE_PROFILE
from .structure import Transaksi
from ..linkaja import (
    WebJob,
    # View as BaseView,
    is_inquiry, RENDERER, get_db_session, is_reversal, is_payment, get_method,
    get_form, date_from_str, csv_method, get_template_response, get_inquiry, get_payment)
from .. import View as BaseView

from ..linkaja.exceptions import (
    InvoiceIdError,
    NeedPostError,
    InternalError,
    HostError,
    AlreadyPaidError,
    BaseError,
    AmountError,
    BillRefNotFound,
    PaymentNotFound,
)
from ..linkaja.models import (Rpc, LogSam)
from ..linkaja.structure import (
    InquiryResponse,
    PaymentResponse,
)

ROUTE = 'linkaja/sambat'

conf = dict()


# def get_inquiry(data):
#     DBSession = get_db_session()
#     bill_ref = int(data['bill_ref'])
#     q = DBSession.query(Rpc).filter_by(id=bill_ref)
#     return q.first()


# def get_payment(data):
#     DBSession = get_db_session()
#     bill_ref = int(data['bill_ref'])
#     q = DBSession.query(Rpc).\
#         filter_by(inquiry_id=bill_ref, trx_type='022')
#     q = q.order_by(Rpc.id.desc())
#     return q.first()


# def get_template_response(data):
#     if is_inquiry(data):
#         return InquiryResponse()
#     d = PaymentResponse()
#     d['Bill Ref'] = data['bill_ref']
#     return d


# view decorator
# class sambat_method(object):
#     def __init__(self, **kw):
#         self.kw = kw
#
#     def __call__(self, wrapped):
#         kw = self.kw.copy()
#         depth = kw.pop('_depth', 0)
#
#         def callback(context, name, ob):
#             config = context.config.with_package(info.module)
#             config.add_view(view=ob, renderer=RENDERER, **kw)
#
#         info = venusian.attach(
#             wrapped, callback, category='pyramid', depth=depth + 1)
#         if info.scope == 'class':
#             # ensure that attr is set if decorating a class method
#             kw.setdefault('attr', wrapped.__name__)
#
#         kw['_info'] = info.codeinfo  # fbo action_method
#         return wrapped


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 = 'Host {} belum terhubung'.format(hostname)
        return InternalError(msg, 'Sedang offline')

    def create_iso_log(self, iso, rpc):
        conf = self.get_iso_conf()
        iso_log = LogSam(
            mti=iso.mti,
            rpc_id=rpc.id,
            ip=conf['ip'],
            conf_name=conf['name'],
            message=iso.data,
            bit_003=iso.data["processingCode"])
        # 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.data["additionalData"]
            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, 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=req.get_stan())
        row.trx_date = date_from_str(data['trx_date']),
        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(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_resp.response
        web_data = get_template_response(data)
        if iso_data["responseCode"] == '00':
            web_data['Response Code'] = '00'
            if is_inquiry(data):
                web_data['Bill Ref'] = str(row.id)
            if iso_data["additionalData"]:
                profile = FixLength(INVOICE_PROFILE)
                profile.set_raw(iso_data["additionalData"])
                iso_log.bit_062_data = profile.to_dict()
                web_data['Biller Name'] = row.biller_name = \
                    ' '.join([profile['NOMOR POLISI'], profile['NAMA PEMILIK'].strip()])
            web_data['Bill Amount'] = iso_data["amountTransaction"].lstrip('0')
            if "numberTransactionP" in iso_data and iso_data["numberTransactionP"]:
                web_data['Transaction ID'] = row.ntp = iso_data["numberTransactionP"]  # NTP
            err = None
        elif iso_data["responseCode"] in ['33', '55']:
            err = InvoiceIdError()
        elif iso_data["responseCode"] == '54':
            if is_reversal(data):
                err = PaymentNotFound()
            else:
                err = AlreadyPaidError()
        elif iso_data["responseCode"] == '51':
            err = AmountError()
        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):
        # todo: merubah get response
        log_web_debug("Start Response")
        p = dict(invoice_id=data['acc_no'])
        inq = pay = None
        if not is_inquiry(data):
            p['amount'] = data['amount']
            p['ntb'] = data['trx_id']
            if is_payment(data):
                inq = get_inquiry(data)
                if not inq:
                    print("Inquiry Not Found")
                    raise BillRefNotFound()
            else:
                pay = get_payment(data)
                if not pay:
                    print("Payment Not Found")
                    raise BillRefNotFound()
                p['stan'] = pay.stan

        # conn = self.get_connection()
        method = get_method(data)
        # iso_func = getattr(conn.job, method)
        iso_req = Transaksi(p, method, inq, pay)
        row = self.before_send_iso(data, inq, pay, iso_req)
        iso_req.send()
        return self.after_send_iso(data, inq, pay, row, iso_req)

    @csv_method(route_name=ROUTE)
    def view_trx_sambat(self):
        self.validate()
        if not self.request.POST:
            self.log_receive('GET {}'.format(self.request.GET))
            raise NeedPostError()
        items = self.request.POST.items()
        self.log_receive('POST {}'.format(dict(items)))
        items = self.request.POST.items()
        form = get_form()
        try:
            c = form.validate(items)
        except ValidationFailure as e:
            d = e.error.asdict()
            msg = e.error
            for field, err in d.items():
                msg = '{} {}'.format(field, err)
                break
            raise InternalError(msg)
        data = dict(c)
        return self.get_response(data)
        # try:
        #     r = self.get_response(data)
        #     self.log_send(r)
        #     return r
        # except BaseError as e:
        #     r = get_template_response(data)
        #     r['Response Code'] = e.code
        #     r['Notification Message'] = e.message
        #     return r

    # @notfound_view_config()
    # def view_not_found(self):
    #     msg = 'Path {} tidak ada'.format(self.request.path)
    #     self.log_receive(msg, True)
    #     return self.request.exception


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


# Dipanggil forwarder.py
def pyramid_init(config):
    # config.add_renderer(RENDERER, 'iso8583_web.scripts.views.linkaja.Renderer')
    config.add_route(ROUTE, conf['route_path'])
    log_web_info('LinkAja Sambat route path {}'.format(conf['route_path']))
    # pool_size = int(conf.get('db_pool_size', 50))
    # max_overflow = int(conf.get('db_max_overflow', 100))
    # engine = create_engine(
    #     conf['db_url'], pool_size=pool_size, max_overflow=max_overflow)
    # session_factory = sessionmaker(bind=engine)
    # conf['db_session'] = scoped_session(session_factory)
    # register(conf['db_session'])