bphtb.py 7.67 KB
import sys
from sqlalchemy import (
    Column,
    Integer,
    DateTime,
    String,
    Date,
    ForeignKey,
    UniqueConstraint,
    func,
    )
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.exc import ProgrammingError
from opensipkd.string import FixLength
from opensipkd.waktu import dmyhms
from opensipkd.bphtb.models.customer import CustomerMixin
from opensipkd.bphtb.models.perolehan import PerolehanMixin
from opensipkd.bphtb.models.invoice import InvoiceMixin
from opensipkd.bphtb.models.payment import PaymentMixin
from opensipkd.bphtb.models.default import (
    Payment,
    Invoice,
    Perolehan,
    Customer,
    )
from opensipkd.bphtb.services.default.structure import INVOICE_ID
from iso8583_web.models.meta import Base as BaseConf
from opensipkd.iso8583.bjb.bphtb import Doc
from opensipkd.iso8583.bjb.bphtb.structure import PAYMENT_CODE
from opensipkd.iso8583.bjb.bphtb.models import Log
from ..models import (
    Base,
    Bphtb,
    )
from .common import (
    get_iso,
    get_channel_name_by_row,
    get_channel_info_by_iso,
    BaseApp,
    init_db as base_init_db,
    one_day,
    InvalidSource,
    )


class AlternativeCustomer(CustomerMixin, Base):
    @declared_attr
    def __table_args__(self):
        return dict(schema='public')


class AlternativePerolehan(PerolehanMixin, Base):
    @declared_attr
    def __table_args__(self):
        return dict(schema='public')


class AlternativeInvoice(InvoiceMixin, Base):
    @declared_attr
    def __table_args__(self):
        return (
            UniqueConstraint('tahun', 'kode', 'no_sspd'),
            dict(schema='public'))


class AlternativePayment(PaymentMixin, Base):
    @declared_attr
    def __table_args__(self):
        return (
            UniqueConstraint('tanggal', 'jam', 'seq', 'transno'),
            dict(schema='public'))


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 App(BaseApp):
    conf_name = 'bphtb payment last date'
    report_orm = Bphtb
    va_product_code = '01'

    def __init__(self, argv):
        super().__init__(argv)
        if not self.pid:
            return
        self.base_q_func = self.prod_session.query(func.count())
        self.base_q_inv = self.prod_session.query(Invoice)
        try:
            self.base_q_inv.first()
            self.Customer = Customer
            self.Perolehan = Perolehan
            self.Invoice = Invoice
            self.Payment = Payment
            self.base_q_cust = self.prod_session.query(self.Customer)
            self.base_q_perolehan = self.prod_session.query(self.Perolehan)
            self.base_q_pay = self.prod_session.query(self.Payment)
        except ProgrammingError:
            self.prod_session.rollback()
            self.Customer = AlternativeCustomer
            self.Perolehan = AlternativePerolehan
            self.Invoice = AlternativeInvoice
            self.Payment = AlternativePayment
            self.base_q_inv = self.prod_session.query(AlternativeInvoice)
            self.base_q_cust = self.prod_session.query(AlternativeCustomer)
            self.base_q_perolehan = self.prod_session.query(
                    AlternativePerolehan)
            self.base_q_pay = self.prod_session.query(AlternativePayment)
        self.base_q_log = self.prod_session.query(Log).filter_by(
            mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
        try:
            self.base_q_log.first()
        except ProgrammingError:
            self.prod_session.rollback()
            self.base_q_log = None

    def get_last_time(self):  # Override
        s_tgl = self.last_pay.tanggal.strftime('%d-%m-%Y')
        s_jam = self.last_pay.jam.strftime('%H:%M:%S')
        return f'{s_tgl} {s_jam}'

    def get_filter_query(self, q):
        return q.filter(
                self.Payment.tanggal >= self.tgl_awal.date(),
                self.Payment.jam >= self.tgl_awal.time(),
                self.Payment.tanggal < self.tgl_akhir + one_day)

    def get_count(self) -> int:  # Override
        q = self.get_filter_query(self.base_q_func)
        return q.scalar()

    def get_payment_query(self):  # Override
        q = self.get_filter_query(self.base_q_pay)
        return q.order_by(self.Payment.tanggal, self.Payment.jam)

    def get_iso_v1(self, pay):
        q = self.prod_session.query(IsoPayment).filter_by(id=pay.id)
        row = q.first()
        if not row:
            return
        iso = get_iso(row.iso_request, Doc, self.option.debug)
        info = get_channel_info_by_iso(iso)
        return info.get('bit_018', '0000'), info['channel'], iso.get_stan(), \
            iso.get_ntb()

    def get_iso_v2(self):
        if not self.base_q_log:
            return
        q = self.base_q_log.filter(func.trim(Log.bit_062) == self.invoice_id)
        q = q.order_by(Log.id.desc())
        row = q.first()
        if not row:
            return
        channel_id = row.bit_018.strip()
        channel_nama = get_channel_name_by_row(row)
        return channel_id, channel_nama, row.bit_011, row.bit_058.strip()

    def get_invoice(self, pay):
        q = self.base_q_inv.filter_by(id=pay.sspd_id)
        return q.first()

    def get_customer(self, inv):
        q = self.base_q_cust.filter_by(id=inv.ppat_id)
        return q.first()

    def get_perolehan(self, inv):
        q = self.base_q_perolehan.filter_by(id=inv.perolehan_id)
        return q.first()

    def create_data(self, pay):  # Override
        if not pay.sspd_id:
            msg = 'Field bphtb_bank.sspd_id NULL'
            raise InvalidSource(msg)
        inv = self.get_invoice(pay)
        if not inv:
            msg = f'Field bphtb_bank.sspd_id {pay.sspd_id} tidak ada di '\
                   'field bphtb_sspd.id'
            raise InvalidSource(msg)
        cust = self.get_customer(inv)
        perolehan = self.get_perolehan(inv)
        invoice_id = FixLength(INVOICE_ID)
        invoice_id['Tahun'] = inv.tahun
        invoice_id['Kode'] = inv.kode
        invoice_id['SSPD No'] = inv.no_sspd
        self.invoice_id = invoice_id.get_raw()
        source = self.get_iso_v2()
        if source:
            channel_id, channel_nama, stan, ntb = source
        else:
            source = self.get_iso_v1(pay)
            if source:
                channel_id, channel_nama, stan, ntb = source
            else:
                stan = ntb = None
                channel_id = '0000'
                channel_nama = self.get_va_channel(pay.tanggal) or 'MANUAL'
        return dict(
            id=pay.id, stan=stan, ntb=ntb, tgl=pay.tanggal, jam=pay.jam,
            invoice_id=self.invoice_id, nop=pay.nop, wp_nama=pay.wp_nama,
            wp_alamat=pay.wp_alamat, op_alamat=inv.op_alamat, npop=pay.npop,
            bumi_luas=pay.bumi_luas, bng_luas=pay.bng_luas,
            nilai_bphtb=pay.bayar, jenis_perolehan=perolehan.nama,
            ppat=cust.nama.strip(), channel_id=channel_id,
            channel_nama=channel_nama)


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)