bphtb_json.py 7.22 KB
import sys
from sqlalchemy import (
    Column,
    Integer,
    DateTime,
    String,
    Date,
    ForeignKey,
    )
import transaction
import datetime
from opensipkd.waktu import (
    dmyhms,
    date_from_str,
    )
from opensipkd.bphtb.models.default import (
    Payment,
    Invoice,
    Perolehan,
    Customer,
    )
from iso8583_web.models.meta import Base as BaseConf
from opensipkd.iso8583.bjb.bphtb import Doc
from ..models import (
    Base,
    Bphtb,
    )
from .common import (
    BaseApp,
    init_db as base_init_db,
    BANK_NAMES,
    )


def get_keys(iso):
    return dict(
            nomor_bayar=iso['no_tagihan'],
            ntb=iso['transno'],
            nama_bank=BANK_NAMES[iso['bankid']])


def get_filter(q):
    return q.filter(IsoPayment.iso_request.like('{%'))


class IsoPayment(Base):
    __tablename__ = 'bphtb_payment'
    __table_args__ = dict(schema='bphtb')
    id = Column(Integer, ForeignKey(Payment.id), primary_key=True)
    tgl = Column(DateTime(timezone=True), nullable=False)
    iso_request = Column(String(1024), nullable=False)
    transmission = Column(DateTime(timezone=True), nullable=False)
    settlement = Column(Date, nullable=False)
    stan = Column(Integer, nullable=False)
    invoice_id = Column(Integer, ForeignKey(Invoice.id), nullable=False)
    invoice_no = Column(String(32), nullable=False)
    ntb = Column(String(32), nullable=False)
    ntp = Column(String(32), nullable=False, unique=True)
    bank_id = Column(Integer)
    channel_id = Column(Integer)
    bank_ip = Column(String(15), nullable=False)


class IsoReversal(Base):
    __tablename__ = 'bphtb_reversal'
    __table_args__ = dict(schema='public')
    id = Column(Integer, ForeignKey(IsoPayment.id), primary_key=True)
    tgl = Column(DateTime(timezone=True), nullable=False)
    iso_request = Column(String(1024), nullable=False)


class App(BaseApp):
    iso_class = Doc
    report_orm = Bphtb
    iso_reversal_orm = IsoReversal

    def __init__(self, argv):
        super().__init__(argv)
        if not self.pid:
            return
        self.base_q_inv = self.prod_session.query(
                Invoice, Customer, Perolehan).filter(
                Invoice.ppat_id == Customer.id,
                Invoice.perolehan_id == Perolehan.id)

    def update_last_id(self, last, value):
        last.nilai = str(value)
        with transaction.manager:
            self.rpt_session.add(last)

    def __warning_nol(self, s_tgl, d, row_pay):
        msg = f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '\
                f'NTB {d["ntb"]}, Channel {d["nama_bank"]}, '\
                f'nilai Rp {row_pay.bayar} tidak disimpan'
        self.log.warning(msg)

    def __log_progress(self, s_tgl, d):
        self.log.info(
            f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
            f'NTB {d["ntb"]}, Channel {d["nama_bank"]}')

    def __get_query_iso(self, last_id):
        q_iso = self.prod_session.query(IsoPayment, Payment).filter(
                IsoPayment.id == Payment.id,
                IsoPayment.id > last_id)
        q_iso = get_filter(q_iso)
        return q_iso.order_by(IsoPayment.id)

    def __create_data(self, row_iso, row_pay, iso, d):
        q_inv = self.base_q_inv.filter(Invoice.id == row_pay.sspd_id)
        inv, ppat, perolehan = q_inv.first()
        return dict(
            stan=row_iso.id, ntb=d['ntb'], tgl=row_iso.tgl,
            jam=row_iso.tgl.time(), invoice_id=d['nomor_bayar'],
            nop=row_pay.nop, wp_nama=row_pay.wp_nama,
            wp_alamat=row_pay.wp_alamat, op_alamat=inv.op_alamat,
            npop=row_pay.npop, bumi_luas=row_pay.bumi_luas,
            bng_luas=row_pay.bng_luas, nilai_bphtb=row_pay.bayar,
            jenis_perolehan=perolehan.nama, ppat=ppat.nama,
            channel_id=int(iso['bankid']), channel_nama=d['nama_bank'])

    def __run_payment(self):
        last = self.get_last_id('bphtb json payment last id')
        q_iso = self.__get_query_iso(last.as_int())
        for row_iso, row_pay in q_iso:
            iso = eval(row_iso.iso_request)
            d = get_keys(iso)
            if self.get_report(d['nomor_bayar'], d['ntb']):
                continue
            s_tgl = dmyhms(row_iso.tgl)
            if not row_pay.bayar:
                self.__warning_nol(s_tgl, d, row_pay)
                self.update_last_id(last, str(row_iso.id))
                continue
            self.__log_progress(s_tgl, d)
            data = self._create_data(row_iso, row_pay, iso, d)
            rpt = Bphtb(**data)
            last.nilai = str(row_iso.id)
            with transaction.manager:
                self.rpt_session.add(rpt)
                self.rpt_session.add(last)

    def __update_from_id(self):
        q_iso = self.__get_query_iso(self.last_id)
        found = False
        for row_iso, row_pay in q_iso.limit(1000):
            iso = eval(row_iso.iso_request)
            d = get_keys(iso)
            s_tgl = dmyhms(row_iso.tgl)
            if not row_pay.bayar:
                self.__warning_nol(s_tgl, d, row_pay)
                continue
            self.__log_progress(s_tgl, d)
            data = self.__create_data(row_iso, row_pay, iso, d)
            rpt = self.get_report(d['nomor_bayar'], d['ntb'])
            if not rpt:
                rpt = Bphtb()
            rpt.from_dict(data)
            with transaction.manager:
                self.rpt_session.add(rpt)
            found = True
            self.last_id = row_iso.id
        return found

    def run_payment(self):  # Override
        if self.option.update_from_id:
            self.last_id = self.option.update_from_id
            func = self.__update_from_id
        elif self.option.update_from_date:
            tgl = date_from_str(self.option.update_from_date)
            q = self.prod_session.query(IsoPayment).filter(
                    IsoPayment.tgl >= tgl).order_by(
                    IsoPayment.id)
            q = get_filter(q)
            row = q.first()
            self.last_id = row.id - 1
            func = self.__update_from_id
        else:
            func = self.__run_payment
        while True:
            found = func()
            if not found:
                break

    def run_reversal(self):  # Override
        last = self.get_last_id('bphtb json reversal last date')
        q = self.prod_session.query(self.iso_reversal_orm).filter(
                self.iso_reversal_orm.iso_request.like('{%'),
                self.iso_reversal_orm.tgl > last.as_datetime())
        for row in q.order_by(self.iso_reversal_orm.tgl):
            iso = eval(row.iso_request)
            invoice_id = iso['bit_061']
            ntb = iso['bit_037']
            rpt = self.get_report(invoice_id, ntb)
            if not rpt or rpt.tgl_batal:
                continue
            nama_bank = BANK_NAMES[iso['bit_032']]
            rpt.tgl_batal = row.tgl
            last.nilai = s_tgl = dmyhms(row.tgl)
            self.log.info(
                f'Tgl batal {s_tgl}, Nomor bayar {invoice_id}, '
                f'NTB {ntb}, Channel {nama_bank}')
            with transaction.manager:
                self.rpt_session.add(rpt)
                self.rpt_session.add(last)


def main(argv=sys.argv[1:]):
    app = App(argv)
    if app.pid:
        app.run()


def init_db(argv=sys.argv[1:]):
    base_init_db(Base.metadata, BaseConf.metadata, argv)