Commit 1b5b288c by Owo Sugiana

Tambah channel VA dan QRIS

1 parent 38f5b1c2
2.0 2022-05-18 2.0 2022-07-17
-------------- --------------
- Perbedaan utama dari versi 0.x adalah kini berangkat dari tabel aslinya dan - Perbedaan utama dari versi 0.x adalah kini berangkat dari tabel aslinya dan
bukan dari tabel ISO8583 karena sudah memperhatikan channel MANUAL (input bukan dari tabel ISO8583 karena sudah memperhatikan channel MANUAL (input
manual pembayaran) manual pembayaran)
- Memahami channel VA dan QRIS
[main] [main]
models = opensipkd.bphtb.models.default models = opensipkd.bphtb.models.default
db_url = postgresql://user:pass@localhost/db db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/bphtb-report.pid pid_file = /home/sugiana/tmp/bphtb-report.pid
log_file = /home/sugiana/log/bphtb-report.log log_file = /home/sugiana/log/bphtb-report.log
[main] [main]
models = opensipkd.pad.models.default models = opensipkd.pad.models.default
db_url = postgresql://user:pass@localhost/db db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/pad-report.pid pid_file = /home/sugiana/tmp/pad-report.pid
log_file = /home/sugiana/log/pad-report.log log_file = /home/sugiana/log/pad-report.log
...@@ -16,6 +16,12 @@ Base = declarative_base() ...@@ -16,6 +16,12 @@ Base = declarative_base()
class Common: class Common:
def to_dict(self):
values = {}
for column in self.__table__.columns:
values[column.name] = getattr(self, column.name)
return values
def from_dict(self, values): def from_dict(self, values):
for column in self.__table__.columns: for column in self.__table__.columns:
if column.name in values: if column.name in values:
...@@ -24,25 +30,24 @@ class Common: ...@@ -24,25 +30,24 @@ class Common:
class Pad(Base, Common): class Pad(Base, Common):
__tablename__ = 'pad_report' __tablename__ = 'pad_report'
# pad.pad_sspd.id
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
# Bit 11 # Bit 11
stan = Column(String(6), nullable=False) stan = Column(String(6))
# Bit 48 # Bit 48
ntb = Column(String(32), nullable=False) ntb = Column(String(32))
# pad.pad_sspd.create_date / log_iso.created # pad.pad_sspd.create_date / log_iso.created
tgl = Column(Date, nullable=False) tgl = Column(Date, nullable=False)
# pad.pad_sspd.sspdjam / log_iso.created # pad.pad_sspd.sspdjam / log_iso.created
jam = Column(Time, nullable=False) jam = Column(Time, nullable=False)
# pad.pad_sspd.id
sspd_id = Column(Integer, nullable=False)
# Bit 61 # Bit 61
nomor_bayar = Column(String(16), nullable=False) nomor_bayar = Column(String(16), nullable=False)
# pad.pad_usaha.usahanm # pad.pad_usaha.usahanm
jenis_pajak = Column(String(32), nullable=False) jenis_pajak = Column(String(64), nullable=False)
# pad.pad_pajak.masapajak # pad.pad_pajak.masapajak
masa_pajak = Column(Integer, nullable=False) masa_pajak = Column(Integer, nullable=False)
# pad.pad_customer.npwpd # pad.pad_customer.npwpd
npwpd = Column(String(17), nullable=False) npwpd = Column(String(17))
# pad.pad_customer.customernm # pad.pad_customer.customernm
nama_wp = Column(String(150), nullable=False) nama_wp = Column(String(150), nullable=False)
# pad.pad_sspd.jml_bayar - pad.pad_sspd.denda # pad.pad_sspd.jml_bayar - pad.pad_sspd.denda
...@@ -59,9 +64,6 @@ class Pad(Base, Common): ...@@ -59,9 +64,6 @@ class Pad(Base, Common):
channel_name = Column(String(32), nullable=False) channel_name = Column(String(32), nullable=False)
# pad_reversal.tgl # pad_reversal.tgl
tgl_batal = Column(DateTime(timezone=True)) tgl_batal = Column(DateTime(timezone=True))
__table_args__ = (
UniqueConstraint('stan', 'ntb'),
)
class Webr(Base, Common): class Webr(Base, Common):
...@@ -90,17 +92,17 @@ class Webr(Base, Common): ...@@ -90,17 +92,17 @@ class Webr(Base, Common):
channel_id = Column(String(4), nullable=False) channel_id = Column(String(4), nullable=False)
# Bit 41 / 42 / 43 # Bit 41 / 42 / 43
channel_name = Column(String(32), nullable=False) channel_name = Column(String(32), nullable=False)
# pad_reversal.tgl
tgl_batal = Column(DateTime(timezone=True)) tgl_batal = Column(DateTime(timezone=True))
class Bphtb(Base, Common): class Bphtb(Base, Common):
__tablename__ = 'bphtb_report' __tablename__ = 'bphtb_report'
# bphtb.bphtb_bank.id
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
# Bit 11 # Bit 11
stan = Column(String(6), nullable=False) stan = Column(String(6))
# Bit 58 # Bit 58
ntb = Column(String(32), nullable=False) ntb = Column(String(32))
# bphtb.bphtb_bank.tanggal # bphtb.bphtb_bank.tanggal
tgl = Column(Date, nullable=False) tgl = Column(Date, nullable=False)
# bphtb.bphtb_bank.jam # bphtb.bphtb_bank.jam
...@@ -133,9 +135,6 @@ class Bphtb(Base, Common): ...@@ -133,9 +135,6 @@ class Bphtb(Base, Common):
channel_nama = Column(String(32), nullable=False) channel_nama = Column(String(32), nullable=False)
# bphtb.bphtb_reversal.tgl # bphtb.bphtb_reversal.tgl
tgl_batal = Column(DateTime(timezone=True)) tgl_batal = Column(DateTime(timezone=True))
__table_args__ = (
UniqueConstraint('stan', 'ntb'),
)
class Pbb(Base, Common): class Pbb(Base, Common):
......
...@@ -6,8 +6,9 @@ from sqlalchemy import ( ...@@ -6,8 +6,9 @@ from sqlalchemy import (
String, String,
Date, Date,
ForeignKey, ForeignKey,
func,
) )
import transaction from opensipkd.string import FixLength
from opensipkd.waktu import dmyhms from opensipkd.waktu import dmyhms
from opensipkd.bphtb.models.default import ( from opensipkd.bphtb.models.default import (
Payment, Payment,
...@@ -15,17 +16,23 @@ from opensipkd.bphtb.models.default import ( ...@@ -15,17 +16,23 @@ from opensipkd.bphtb.models.default import (
Perolehan, Perolehan,
Customer, Customer,
) )
from opensipkd.bphtb.services.default.structure import INVOICE_ID
from iso8583_web.models.meta import Base as BaseConf from iso8583_web.models.meta import Base as BaseConf
from opensipkd.iso8583.bjb.bphtb import Doc 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 ( from ..models import (
Base, Base,
Bphtb, Bphtb,
) )
from .common import ( from .common import (
get_iso, get_iso,
get_keys, get_channel_name_by_row,
App as BaseApp, get_channel_info_by_iso,
BaseApp,
init_db as base_init_db, init_db as base_init_db,
one_day,
InvalidSource,
) )
...@@ -47,70 +54,105 @@ class IsoPayment(Base): ...@@ -47,70 +54,105 @@ class IsoPayment(Base):
bank_ip = Column(String(15), nullable=False) 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): class App(BaseApp):
iso_class = Doc conf_name = 'bphtb payment last date'
report_orm = Bphtb report_orm = Bphtb
va_product_code = '01'
def __init__(self, argv): def __init__(self, argv):
super().__init__(argv) super().__init__(argv)
if not self.pid: if not self.pid:
return return
self.base_q_inv = self.prod_session.query( self.base_q_inv = self.prod_session.query(Invoice)
Invoice, Customer, Perolehan).filter( self.base_q_cust = self.prod_session.query(Customer)
Invoice.ppat_id == Customer.id, self.base_q_perolehan = self.prod_session.query(Perolehan)
Invoice.perolehan_id == Perolehan.id)
def get_last_time(self): # Override
def run_payment(self): # Override s_tgl = self.last_pay.tanggal.strftime('%d-%m-%Y')
last = self.get_last_id('bphtb payment last id') s_jam = self.last_pay.jam.strftime('%H:%M:%S')
q_iso = self.prod_session.query(IsoPayment, Payment).filter( return f'{s_tgl} {s_jam}'
IsoPayment.id == Payment.id,
IsoPayment.id > last.as_int()) def get_filter_query(self, q):
for row_iso, row_pay in q_iso.order_by(IsoPayment.id): return q.filter(
if row_iso.iso_request[0] == '{': Payment.tanggal >= self.tgl_awal.date(),
last.nilai = str(row_iso.id) Payment.jam >= self.tgl_awal.time(),
with transaction.manager: Payment.tanggal < self.tgl_akhir + one_day)
self.rpt_session.add(last)
continue def get_count(self) -> int: # Override
iso = get_iso(row_iso.iso_request, Doc, self.option.debug) q = self.prod_session.query(func.count())
if self.get_report(iso): q = self.get_filter_query(q)
continue return q.scalar()
tgl_bayar = row_iso.tgl.date()
q_inv = self.base_q_inv.filter(Invoice.id == row_pay.sspd_id) def get_payment_query(self): # Override
inv, ppat, perolehan = q_inv.first() q = self.prod_session.query(Payment)
d = get_keys(iso) q = self.get_filter_query(q)
s_tgl = dmyhms(row_iso.tgl) return q.order_by(Payment.tanggal, Payment.jam)
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, ' def get_iso_v1(self, pay):
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}') q = self.prod_session.query(IsoPayment).filter_by(id=pay.id)
rpt = Bphtb( row = q.first()
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar, if not row:
jam=row_iso.tgl.time(), return
invoice_id=iso.get_invoice_id().strip(), iso = get_iso(row.iso_request, Doc, self.option.debug)
nop=row_pay.nop, wp_nama=row_pay.wp_nama, info = get_channel_info_by_iso(iso)
wp_alamat=row_pay.wp_alamat, op_alamat=inv.op_alamat, return info['bit_018'], info['channel'], iso.get_stan(), iso.get_ntb()
npop=row_pay.npop, bumi_luas=row_pay.bumi_luas,
bng_luas=row_pay.bng_luas, nilai_bphtb=row_pay.bayar, def get_iso_v2(self):
jenis_perolehan=perolehan.nama, ppat=ppat.nama, q = self.prod_session.query(Log).filter_by(
channel_id=iso.get_channel().strip(), mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
channel_nama=d['channel']) q = q.filter(func.trim(Log.bit_062) == self.invoice_id)
last.nilai = str(row_iso.id) q = q.order_by(Log.id.desc())
with transaction.manager: row = q.first()
self.rpt_session.add(rpt) if not row:
self.rpt_session.add(last) return
channel_id = row.bit_018.strip()
def get_iso_reversal_orm(self): # Override channel_nama = get_channel_name_by_row(row)
return IsoReversal return channel_id, channel_nama, row.bit_011, row.bit_058.strip()
def run_reversal(self): # Override def get_invoice(self, pay):
super().run_reversal('bphtb reversal last date') 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
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:]): def main(argv=sys.argv[1:]):
......
import sys
from sqlalchemy.exc import ProgrammingError
import transaction
from opensipkd.waktu import (
dmyhms,
date_from_str,
)
from opensipkd.bphtb.models.perolehan import PerolehanMixin
from opensipkd.bphtb.models.default import Perolehan
from iso8583_web.models.meta import Base as BaseConf
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 (
App2 as BaseApp,
init_db as base_init_db,
)
class AlternativePerolehan(Base, PerolehanMixin):
__table_args__ = dict(schema='public')
def error(s):
print(s)
sys.exit()
class App(BaseApp):
field_invoice_id = 'bit_062'
field_ntb = 'bit_058'
report_orm = Bphtb
def __init__(self, argv):
super().__init__(argv)
if not self.pid:
return
self.base_q_perolehan = self.prod_session.query(Perolehan)
with transaction.manager:
try:
self.base_q_perolehan.first()
except ProgrammingError:
self.prod_session.rollback()
self.base_q_perolehan = self.prod_session.query(
AlternativePerolehan)
def get_log_orm(self): # Override
return Log
def __create_data(self, row_iso):
tgl_bayar = row_iso.created.date()
d = self.get_keys(row_iso)
s_tgl = dmyhms(row_iso.created)
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
p = eval(row_iso.bit_047_data)
q = self.base_q_perolehan.filter_by(id=p['Jenis Perolehan Hak'])
perolehan = q.first()
return dict(
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar,
jam=row_iso.created.time(),
invoice_id=row_iso.bit_062.strip(),
nop=row_iso.bit_061.strip(),
wp_nama=p['Nama Wajib Pajak'],
wp_alamat=p['Alamat WP'],
op_alamat=p['Alamat OP'],
npop=p['NPOP'],
bumi_luas=p['Luas Tanah'],
bng_luas=p['Luas Bangunan'],
nilai_bphtb=float(row_iso.bit_004),
jenis_perolehan=perolehan.nama,
ppat=p['Nama Notaris'],
channel_id=row_iso.bit_018.strip(),
channel_nama=d['channel'])
def __get_query_iso(self, last_id):
return self.prod_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00').filter(
Log.id > last_id)
def __run_payment(self):
last = self.get_last_id('bphtb2 payment last id')
q_iso = self.__get_query_iso(last.as_int())
found = False
for row_iso in q_iso.order_by(Log.id).limit(1000):
if self.get_report(row_iso):
last.nilai = str(row_iso.id)
with transaction.manager:
self.rpt_session.add(last)
continue
data = self.__create_data(row_iso)
rpt = Bphtb(**data)
last.nilai = str(row_iso.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
found = True
return found
def __update_from_id(self):
q_iso = self.__get_query_iso(self.last_id)
found = False
for row_iso in q_iso.order_by(Log.id).limit(1000):
rpt = self.get_report(row_iso)
if not rpt:
rpt = Bphtb()
data = self.__create_data(row_iso)
rpt.from_dict(data)
with transaction.manager:
self.rpt_session.add(rpt)
self.last_id = row_iso.id
found = True
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(Log).filter(Log.created >= tgl)
q = q.order_by(Log.id)
row = q.first()
if not row:
error('Kosong')
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
super().run_reversal('bphtb2 reversal last id')
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)
...@@ -2,22 +2,36 @@ import sys ...@@ -2,22 +2,36 @@ import sys
import os import os
import logging import logging
import csv import csv
from time import time
from datetime import ( from datetime import (
date, date,
datetime, datetime,
timedelta,
) )
from argparse import ArgumentParser from argparse import ArgumentParser
from configparser import ConfigParser from configparser import ConfigParser
from ISO8583.ISO8583 import BitNotSet from ISO8583.ISO8583 import BitNotSet
from sqlalchemy import create_engine from sqlalchemy import (
Column,
String,
Integer,
ForeignKey,
create_engine,
)
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
import transaction import transaction
from zope.sqlalchemy import register from zope.sqlalchemy import register
from opensipkd.waktu import dmyhms
from opensipkd.views.models import Conf as BaseConf from opensipkd.views.models import Conf as BaseConf
from opensipkd.iso8583.bjb.scripts.common import get_module_object from opensipkd.iso8583.bjb.scripts.common import get_module_object
from ..models import Base from ..models import Base
from .tools import (
plain_values,
update,
)
one_day = timedelta(1)
row_limit = 1000
log_format = '%(asctime)s %(levelname)s %(message)s' log_format = '%(asctime)s %(levelname)s %(message)s'
formatter = logging.Formatter(log_format) formatter = logging.Formatter(log_format)
...@@ -54,6 +68,31 @@ BANK_NAMES = {'700': 'PT POS'} ...@@ -54,6 +68,31 @@ BANK_NAMES = {'700': 'PT POS'}
my_registry = dict() my_registry = dict()
class InvalidSource(Exception):
pass
class VaInvoice(Base):
__tablename__ = 'bjb_va_invoice'
id = Column(Integer, primary_key=True)
va_type = Column(String(8))
product_code = Column(String(16))
invoice_no = Column(String(64))
class VaPayment(Base):
__tablename__ = 'bjb_va_payment'
id = Column(Integer, primary_key=True)
va_invoice_id = Column(Integer, ForeignKey(VaInvoice.id))
transaction_date = Column(String(32))
def humanize_time(secs):
mins, secs = divmod(secs, 60)
hours, mins = divmod(mins, 60)
return '%02d:%02d:%02d' % (hours, mins, secs)
def get_file(filename): def get_file(filename):
base_dir = os.path.split(__file__)[0] base_dir = os.path.split(__file__)[0]
fullpath = os.path.join(base_dir, 'data', filename) fullpath = os.path.join(base_dir, 'data', filename)
...@@ -170,7 +209,6 @@ def create_log(log_file): ...@@ -170,7 +209,6 @@ def create_log(log_file):
def get_parser(): def get_parser():
pars = ArgumentParser() pars = ArgumentParser()
pars.add_argument('conf') pars.add_argument('conf')
pars.add_argument('--update-from-id', type=int)
pars.add_argument('--update-from-date') pars.add_argument('--update-from-date')
pars.add_argument('--debug', action='store_true') pars.add_argument('--debug', action='store_true')
pars.add_argument('--debug-sql', action='store_true') pars.add_argument('--debug-sql', action='store_true')
...@@ -228,6 +266,10 @@ def make_pid_file(filename): ...@@ -228,6 +266,10 @@ def make_pid_file(filename):
class BaseApp: class BaseApp:
conf_name = None # Override, please
report_orm = None # Override, please
va_product_code = '' # Override, please
def __init__(self, argv): def __init__(self, argv):
self.option = get_option(argv) self.option = get_option(argv)
cp = ConfigParser() cp = ConfigParser()
...@@ -239,12 +281,23 @@ class BaseApp: ...@@ -239,12 +281,23 @@ class BaseApp:
self.log = create_log(self.conf['log_file']) self.log = create_log(self.conf['log_file'])
if 'models' in self.conf: if 'models' in self.conf:
self.models = get_module_object(self.conf['models']) self.models = get_module_object(self.conf['models'])
if 'service' in self.conf:
self.service = get_module_object(self.conf['service'])
module_conf = dict(self.conf) module_conf = dict(self.conf)
factory = self.get_factory('db_url') factory = self.get_factory('db_url')
self.prod_session = factory() self.prod_session = factory()
factory = self.get_factory('report_db_url') factory = self.get_factory('report_db_url')
self.rpt_session = factory() self.rpt_session = factory()
register(self.rpt_session) register(self.rpt_session)
if 'va_db_url' in self.conf:
factory = self.get_factory('va_db_url')
self.va_session = factory()
self.base_q_va = self.va_session.query(VaPayment, VaInvoice).\
filter(
VaPayment.va_invoice_id == VaInvoice.id,
VaInvoice.product_code == self.va_product_code)
else:
self.va_session = None
def get_factory(self, name): def get_factory(self, name):
db_url = self.conf[name] db_url = self.conf[name]
...@@ -255,114 +308,125 @@ class BaseApp: ...@@ -255,114 +308,125 @@ class BaseApp:
q = self.rpt_session.query(Conf).filter_by(nama=nama) q = self.rpt_session.query(Conf).filter_by(nama=nama)
return q.first() return q.first()
def get_report(self, stan, ntb): def get_payment_query(self): # Override, please
q = self.base_q_report.filter_by(stan=stan, ntb=ntb)
return q.first()
def run_payment(self): # Override, please
pass pass
def run_reversal(self): # Override, please def create_data(self, pay): # Override, please
pass pass
def run(self): def get_report(self, pay):
if not self.pid: q = self.rpt_session.query(self.report_orm).filter_by(id=pay.id)
return return q.first()
self.run_payment()
self.run_reversal()
# Tanpa tabel log_iso
class App(BaseApp):
def get_report(self, iso): # Override
d = get_keys(iso)
return super().get_report(d['stan'], d['ntb'])
def get_iso_reversal_orm(self): # Override, please
return
def get_doc_for_reversal(row): # Override, please
return
def run_reversal(self, conf_name): # Override def update_from_date(self):
last = self.get_last_id(conf_name) q = self.get_payment_query()
orm = self.get_iso_reversal_orm() no = self.offset
q = self.prod_session.query(orm).filter(orm.tgl > last.as_datetime()) found = False
for row in q.order_by(orm.tgl): for pay in q.offset(self.offset).limit(row_limit):
if row.iso_request[0] == '{': found = True
last.nilai = dmyhms(row.tgl) no += 1
try:
source = self.create_data(pay)
d = plain_values(source)
rpt = self.get_report(pay)
if rpt:
target = rpt.to_dict()
target_update, log_msg = update(source, target)
if target_update:
s = ', '.join(log_msg)
msg = f'UPDATE {d} change {s}'
rpt.from_dict(target_update)
else:
msg = f'ALREADY SAME {d}'
rpt = None
else:
msg = f'INSERT {d}'
rpt = self.report_orm(**source)
msg = f'Invoice ID {self.invoice_id} {msg}'
log_method = self.log.info
except InvalidSource as e:
msg = str(e)
log_method = self.log.warning
rpt = None
duration = time() - self.start_time
speed = duration / no
remain_row = self.count - no
e = humanize_time(speed * remain_row)
log_method(f'#{no}/{self.count} {msg}, estimate {e}')
if rpt:
with transaction.manager: with transaction.manager:
self.rpt_session.add(last) self.rpt_session.add(rpt)
continue self.last_pay = pay
Doc = self.get_doc_for_reversal(row) self.offset += row_limit
iso = get_iso(row.iso_request, Doc, self.option.debug) return found
rpt = self.get_report(iso)
if not rpt or rpt.tgl_batal: def get_last_time(self): # Override, please
continue pass
rpt.tgl_batal = row.tgl
last.nilai = s_tgl = dmyhms(row.tgl)
d = get_keys(iso)
self.log.info(
f'Tgl batal {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
def update_last(self):
self.last.nilai = self.get_last_time()
with transaction.manager:
self.rpt_session.add(self.last)
# Dengan tabel log_iso def get_count(self): # Override, please
pass
class App2(BaseApp): def run_payment(self):
field_invoice_id = None # Override, please self.last_pay = None
field_ntb = None # Override, please self.last = None
self.offset = 0
self.tgl_akhir = date.today()
if self.option.update_from_date:
try:
days_ago = int(self.option.update_from_date)
self.tgl_awal = date.today() + timedelta(days_ago)
except ValueError:
t = self.option.update_from_date.split(',')
self.tgl_awal = datetime.strptime(t[0], '%d-%m-%Y')
if t[1:]:
self.tgl_akhir = datetime.strptime(t[1], '%d-%m-%Y')
else:
self.last = self.get_last_id(self.conf_name)
self.tgl_awal = self.last.as_datetime()
self.count = self.get_count()
self.start_time = time()
while True:
found = self.update_from_date()
if not found:
break
if self.last_pay and self.last:
self.update_last()
def get_log_orm(self): # Override, please def run(self):
return if not self.pid:
return
self.run_payment()
def get_stan(self, row): def get_va_channel(self, pay_date):
return row.bit_011.strip() if not self.va_session:
return
def get_invoice_id(self, row): q = self.base_q_va.filter(VaInvoice.invoice_no == self.invoice_id)
s = getattr(row, self.field_invoice_id) q = q.order_by(VaPayment.id.desc())
return s.strip() row = q.first()
if not row:
def get_ntb(self, row): return
s = getattr(row, self.field_ntb) va_pay, va_inv = row
return s.strip() va_pay_date = datetime.strptime(
va_pay.transaction_date, '%Y-%m-%d %H:%M:%S')
def get_report(self, row): # Override va_pay_date = va_pay_date.date()
stan = self.get_stan(row) if va_pay_date != pay_date:
ntb = self.get_ntb(row) msg = f'Invoice ID {self.invoice_id} ada pembayaran melalui '\
return super().get_report(stan, ntb) f'VA/QRIS tapi tanggalnya beda yaitu {pay_date} vs '\
f'{va_pay_date}'
def get_keys(self, row): self.log.warning(msg)
return dict( return
nomor_bayar=self.get_invoice_id(row), if va_inv.va_type == 'a':
stan=self.get_stan(row), return 'VA'
ntb=self.get_ntb(row), if va_inv.va_type == 'q':
channel=get_channel_name_by_row(row)) return 'QRIS'
raise Exception(
def run_reversal(self, conf_name): # Override f'Invoice ID {invoice_id} va_type {inv.va_type} '
last = self.get_last_id(conf_name) 'belum dipahami, perbaiki script')
orm = self.get_log_orm()
q = self.prod_session.query(orm).filter_by(
mti='0410', bit_039='00').filter(
orm.id > last.id)
for row in q.order_by(orm.id):
rpt = self.get_report(row)
if not rpt or rpt.tgl_batal:
continue
rpt.tgl_batal = row.created
s_tgl = dmyhms(row.created)
last.nilai = row.id
d = self.get_keys(row)
self.log.info(
f'Tgl batal {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
def init_db(argv=sys.argv[1:]): def init_db(argv=sys.argv[1:]):
......
nama,nilai,keterangan nama,nilai,keterangan
pad payment last id,0,pad_payment.id terakhir yang diproses pad payment last date,1-1-2000 00:00:00,pad.pad_sspd.sspdtgl terakhir yang diproses
pad reversal last date,1-1-2000 00:00:00,pad_reversal.tgl terakhir yang diproses pad reversal last date,1-1-2000 00:00:00,pad_reversal.tgl terakhir yang diproses
pad json payment last id,0,pad_payment.id terakhir yang diproses pad json payment last id,0,pad_payment.id terakhir yang diproses
pad json reversal last date,1-1-2000 00:00:00,pad_reversal.tgl terakhir yang diproses pad json reversal last date,1-1-2000 00:00:00,pad_reversal.tgl terakhir yang diproses
pad2 payment last id,0,log_iso.id terakhir yang diproses webr payment last date,1-1-2000 00:00:00,webr.ar_payment.created terakhir yang diproses
pad2 reversal last id,0,log_iso.id terakhir yang diproses bphtb payment last date,01-01-2000 00:00:00,bphtb.bphtb_bank.tanggal terakhir yang diproses
webr payment last id,0,log_iso.id terakhir yang diproses
webr2 payment last id,0,log_iso.id terakhir yang diproses
webr2 reversal last id,0,log_iso.id terakhir yang diproses
bphtb payment last id,0,bphtb.bphtb_payment.id terakhir yang diproses
bphtb reversal last date,1-1-2000 00:00:00,bphtb.bphtb_reversal.tgl terakhir yang diproses
bphtb json payment last id,0,bphtb.bphtb_payment.id terakhir yang diproses
bphtb json reversal last date,1-1-2000 00:00:00,bphtb.bphtb_reversal.tgl terakhir yang diproses
bphtb2 payment last id,0,log_iso.id terakhir yang diproses
bphtb2 reversal last id,0,log_iso.id terakhir yang diproses
pbb payment last date,1-1-2000,pembayaran_sppt.tgl_rekam_byr_sppt terakhir yang diproses pbb payment last date,1-1-2000,pembayaran_sppt.tgl_rekam_byr_sppt terakhir yang diproses
pbb reversal last date,1-1-2000 00:00:00,reversal.tgl terakhir yang diproses
pbb2 payment last id,0,log_iso.id terakhir yang diproses
pbb2 reversal last id,0,log_iso.id terakhir yang diproses
va pbb last id,0,pembayaran_sppt.id terakhir yang diproses
import sys import sys
from datetime import timedelta from datetime import (
import transaction date,
from opensipkd.waktu import ( datetime,
dmyhms,
date_from_str,
) )
from sqlalchemy import func
from opensipkd.string import FixLength
from opensipkd.waktu import dmyhms
from opensipkd.pad.models.default import ( from opensipkd.pad.models.default import (
Payment,
IsoPayment, IsoPayment,
IsoReversal,
) )
from iso8583_web.models.meta import Base as BaseConf from iso8583_web.models.meta import Base as BaseConf
from opensipkd.iso8583.bjb.pad.structure import PAYMENT_CODE
from opensipkd.iso8583.bjb.pad.doc import Doc as BjbDoc from opensipkd.iso8583.bjb.pad.doc import Doc as BjbDoc
from opensipkd.iso8583.bjb.pad.models import Log
from opensipkd.iso8583.multi.doc import Doc as MultiDoc from opensipkd.iso8583.multi.doc import Doc as MultiDoc
from ..models import ( from ..models import (
Base, Base,
...@@ -18,22 +21,25 @@ from ..models import ( ...@@ -18,22 +21,25 @@ from ..models import (
) )
from .common import ( from .common import (
get_iso, get_iso,
get_keys, get_channel_info_by_iso,
App as BaseApp, get_channel_name_by_row,
BaseApp,
init_db as base_init_db, init_db as base_init_db,
one_day,
) )
BankHandlers = { BankHandlers = {
8: MultiDoc, 8: MultiDoc,
14: MultiDoc, 14: MultiDoc,
110: BjbDoc, 110: BjbDoc,
700: MultiDoc} 700: MultiDoc}
ERR_NOT_FOUND = 'Tgl {tgl_bayar} pad.pad_sspd.spt_id {invoice_id} tidak ada'
class App(BaseApp): class App(BaseApp):
conf_name = 'pad payment last date'
report_orm = Pad report_orm = Pad
va_product_code = '10'
def __init__(self, argv): def __init__(self, argv):
super().__init__(argv) super().__init__(argv)
...@@ -53,132 +59,83 @@ class App(BaseApp): ...@@ -53,132 +59,83 @@ class App(BaseApp):
Invoice.customer_usaha_id == CustomerUsaha.id, Invoice.customer_usaha_id == CustomerUsaha.id,
CustomerUsaha.customer_id == Customer.id, CustomerUsaha.customer_id == Customer.id,
Usaha.id == Pajak.usaha_id,) Usaha.id == Pajak.usaha_id,)
self.base_q_iso = self.prod_session.query(IsoPayment) self.base_q_log = self.prod_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
def get_pay(self, row):
tgl_bayar = row.tgl.date() def get_pay_date(self): # Override
Payment = self.models.Payment return self.last_pay.sspdtgl.date()
q_pay = self.base_q_pay.filter_by(spt_id=row.invoice_id).filter(
Payment.create_date >= tgl_bayar, def get_last_time(self): # Override
Payment.create_date < tgl_bayar + timedelta(1)) return dmyhms(self.last_pay.sspdtgl)
q_pay = q_pay.order_by(Payment.id.desc())
return q_pay.first() def get_filter_query(self, q):
return q.filter(
def __get_query_iso(self, last_id): Payment.sspdtgl >= self.tgl_awal,
q_iso = self.base_q_iso.filter(IsoPayment.id > last_id) Payment.sspdtgl < self.tgl_akhir + one_day)
return q_iso.order_by(IsoPayment.id)
def get_count(self): # Override
q = self.prod_session.query(func.count())
q = self.get_filter_query(q)
return q.scalar()
def get_payment_query(self): # Override
q = self.prod_session.query(Payment)
q = self.get_filter_query(q)
return q.order_by(Payment.sspdtgl)
def get_iso_v1(self, pay):
q = self.prod_session.query(IsoPayment).filter_by(id=pay.id)
row = q.first()
if not row:
return
Doc = BankHandlers[row.bank_id]
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(), row.bank_id
def get_iso_v2(self):
q = self.base_q_log.filter(func.trim(Log.bit_061) == 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_048.strip(), int(row.bit_032)
def __create_data(self, row, pay, iso, d, tgl_bayar): def create_data(self, pay): # Override
Invoice = self.models.Invoice Invoice = self.models.Invoice
q_inv = self.base_q_inv.filter(Invoice.id == pay.spt_id) q_inv = self.base_q_inv.filter(Invoice.id == pay.spt_id)
inv, pajak, cust, usaha = q_inv.first() inv, pajak, cust, usaha = q_inv.first()
return dict( invoice_id = FixLength(self.service.INVOICE_ID)
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar, invoice_id['Tahun'] = inv.tahun
jam=row.tgl.time(), sspd_id=pay.id, invoice_id['SptNo'] = inv.sptno
nomor_bayar=iso.get_invoice_id().strip(), prefix = getattr(self.service, 'PREFIX')
jenis_pajak=usaha.usahanm.strip(), if prefix:
masa_pajak=pajak.masapajak, npwpd=cust.npwpd, invoice_id['Prefix'] = prefix
nama_wp=cust.customernm, pokok=pay.jml_bayar-pay.denda, self.invoice_id = invoice_id.get_raw()
denda=pay.denda, jml_bayar=pay.jml_bayar, source = self.get_iso_v2()
channel_id=iso.get_channel().strip(), if source:
channel_name=d['channel'], bank_id=iso.get_bank_id()) channel_id, channel_name, stan, ntb, bank_id = source
def __log_progress(self, s_tgl, d):
self.log.info(f'Tgl bayar {s_tgl}, {d}')
def __run_payment(self):
last = self.get_last_id('pad payment last id')
q_iso = self.__get_query_iso(last.as_int())
found = False
for row in q_iso.order_by(IsoPayment.id).limit(1000):
if row.iso_request[0] == '{':
last.nilai = str(row.id)
with transaction.manager:
self.rpt_session.add(last)
continue
Doc = BankHandlers[row.bank_id]
iso = get_iso(row.iso_request, Doc, self.option.debug)
if self.get_report(iso):
continue
pay = self.get_pay(row)
tgl_bayar = row.tgl.date()
if not pay:
msg = ERR_NOT_FOUND.format(
tgl_bayar=tgl_bayar, invoice_id=row.invoice_id)
self.log.error(msg)
continue
d = get_keys(iso)
s_tgl = dmyhms(row.tgl)
data = self.__create_data(row, pay, iso, d, tgl_bayar)
self.__log_progress(s_tgl, data)
rpt = Pad(**data)
last.nilai = str(row.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
found = True
return found
def __update_from_id(self):
q_iso = self.__get_query_iso(self.last_id)
found = False
for row in q_iso.order_by(IsoPayment.id).limit(1000):
if row.iso_request[0] == '{':
last.nilai = str(row.id)
with transaction.manager:
self.rpt_session.add(last)
Doc = BankHandlers[row.bank_id]
iso = get_iso(row.iso_request, Doc, self.option.debug)
tgl_bayar = row.tgl.date()
pay = self.get_pay(row)
rpt = self.get_report(iso)
if not rpt:
if not pay:
msg = ERR_NOT_FOUND.format(
tgl_bayar=tgl_bayar, invoice_id=row.invoice_id)
self.log.error(msg)
continue
rpt = Pad()
d = get_keys(iso)
s_tgl = dmyhms(row.tgl)
data = self.__create_data(row, pay, iso, d, tgl_bayar)
self.__log_progress(s_tgl, data)
rpt.from_dict(data)
with transaction.manager:
self.rpt_session.add(rpt)
found = True
self.last_id = row.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)
row = q.first()
self.last_id = row.id - 1
func = self.__update_from_id
else: else:
func = self.__run_payment source = self.get_iso_v1(pay)
while True: if source:
found = func() channel_id, channel_name, stan, ntb, bank_id = source
if not found: else:
break stan = ntb = bank_id = None
channel_id = '0000'
def get_iso_reversal_orm(self): # Override tgl = pay.sspdtgl.date()
return IsoReversal channel_name = self.get_va_channel(tgl) or 'MANUAL'
return dict(
def get_doc_for_reversal(self, row): # Override id=pay.id, stan=stan, ntb=ntb, tgl=pay.sspdtgl.date(),
q = self.prod_session.query(IsoPayment).filter_by(id=row.id) jam=pay.sspdtgl.time(), nomor_bayar=invoice_id.get_raw(),
iso_pay = q.first() jenis_pajak=usaha.usahanm.strip(), masa_pajak=pajak.masapajak,
return BankHandlers[iso_pay.bank_id] npwpd=cust.npwpd, nama_wp=cust.customernm,
pokok=pay.jml_bayar-pay.denda, denda=pay.denda,
def run_reversal(self): # Override jml_bayar=pay.jml_bayar, channel_id=channel_id,
super().run_reversal('pad reversal last date') channel_name=channel_name, bank_id=bank_id)
def main(argv=sys.argv[1:]): def main(argv=sys.argv[1:]):
......
import sys
import transaction
from opensipkd.waktu import dmyhms
from opensipkd.pad.models.default import (
Payment,
Invoice,
Pajak,
CustomerUsaha,
Customer,
Usaha,
)
from opensipkd.iso8583.bjb.pad.structure import PAYMENT_CODE
from opensipkd.iso8583.bjb.pad.models import (
Log,
PadLog,
)
from iso8583_web.models.meta import Base as BaseConf
from ..models import (
Base,
Pad,
)
from .common import (
App2 as BaseApp,
init_db as base_init_db,
)
ERR_NOT_FOUND = 'Tgl {tgl_bayar} nomor bayar {invoice_id} tidak ada'
class App(BaseApp):
field_invoice_id = 'bit_061'
field_ntb = 'bit_048'
report_orm = Pad
log_orm = Log
def __init__(self, argv):
super().__init__(argv)
if not self.pid:
return
self.base_q_iso_resp = self.prod_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE)
self.base_q_pay = self.prod_session.query(Payment).filter(
PadLog.sspd_id == Payment.id)
self.base_q_inv = self.prod_session.query(
Invoice, Pajak, Customer, Usaha)
self.base_q_inv = self.base_q_inv.filter(
Invoice.pajak_id == Pajak.id,
Invoice.customer_usaha_id == CustomerUsaha.id,
CustomerUsaha.customer_id == Customer.id,
Usaha.id == Pajak.usaha_id,)
def get_pay(self, iso_req):
q_pay = self.base_q_pay.filter(PadLog.id == iso_req.id)
return q_pay.first()
def is_iso_resp_ok(self, iso_req):
q = self.base_q_iso_resp.filter_by(
bit_011=iso_req.bit_011, bit_048=iso_req.bit_048)
iso_resp = q.order_by(Log.id.desc()).first()
return iso_resp and iso_resp.bit_039 == '00'
def run_payment(self):
last = self.get_last_id('pad2 payment last id')
q_iso_req = self.prod_session.query(Log).filter_by(
mti='0200', bit_003=PAYMENT_CODE).filter(
Log.id > last.as_int())
for iso_req in q_iso_req.order_by(Log.id):
if self.get_report(iso_req):
continue
if not self.is_iso_resp_ok(iso_req):
continue
d = self.get_keys(iso_req)
tgl_bayar = iso_req.created.date()
pay = self.get_pay(iso_req)
if not pay:
msg = ERR_NOT_FOUND.format(
tgl_bayar=tgl_bayar, invoice_id=d['nomor_bayar'])
self.log.error(msg)
continue
s_tgl = dmyhms(iso_req.created)
q_inv = self.base_q_inv.filter(Invoice.id == pay.spt_id)
inv, pajak, cust, usaha = q_inv.first()
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'Jenis Pajak {usaha.usahanm.strip()},'
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
rpt = Pad(
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar,
jam=iso_req.created.time(), sspd_id=pay.id,
nomor_bayar=d['nomor_bayar'],
jenis_pajak=usaha.usahanm.strip(),
masa_pajak=pajak.masapajak, npwpd=cust.npwpd,
nama_wp=cust.customernm, pokok=pay.jml_bayar-pay.denda,
denda=pay.denda, jml_bayar=pay.jml_bayar,
channel_id=iso_req.bit_018.strip(),
channel_name=d['channel'])
last.nilai = str(iso_req.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
def run_reversal(self): # Override
super().run_reversal('pad2 reversal last id')
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)
...@@ -19,104 +19,29 @@ from opensipkd.waktu import ( ...@@ -19,104 +19,29 @@ from opensipkd.waktu import (
) )
from opensipkd.iso8583.bjb.scripts.common import get_module_object from opensipkd.iso8583.bjb.scripts.common import get_module_object
from opensipkd.iso8583.bjb.pbb.default import Doc from opensipkd.iso8583.bjb.pbb.default import Doc
from opensipkd.iso8583.bjb.pbb.structure import INVOICE_PROFILE from opensipkd.iso8583.bjb.pbb.structure import PAYMENT_CODE
from ..models import Pbb from opensipkd.iso8583.bjb.pbb.models import Log
from ..models import (
Pbb,
Base,
)
from .common import ( from .common import (
get_iso, get_iso,
get_channel_info_by_iso, get_channel_info_by_iso,
get_channel_name_by_row,
BaseApp, BaseApp,
one_day,
VaInvoice,
VaPayment,
InvalidSource,
) )
class SpptNotFound(Exception):
pass
one_second = timedelta(1/24/60/60)
one_day = timedelta(1)
row_limit = 1000
log_psppt_fields = (
'tgl_rekam_byr_sppt', 'jml_sppt_yg_dibayar', 'nip_rekam_byr_sppt',
'kd_kanwil', 'kd_kantor', 'kd_tp')
log_iso_bits = [
(4, int),
(11, str),
(48, str)]
def get_log_row(row, fieldnames):
r = dict()
for fieldname in fieldnames:
val = getattr(row, fieldname)
if isinstance(val, datetime):
val = to_str(val)
elif isinstance(val, str):
val = val.strip()
r[fieldname] = val
return r
def log_psppt_msg(psppt):
invoice_id = get_id(psppt)
log_psppt = get_log_row(psppt, log_psppt_fields)
return f'ID {invoice_id} ke {psppt.pembayaran_sppt_ke}, '\
f'psppt {log_psppt}'
def get_log_iso(iso, bits):
r = dict()
for bit, f in bits:
val = iso.getBit(bit)
if f == str:
val = val.strip()
else:
val = f(val)
r[bit] = val
return r
def log_iso_msg(iso):
r = get_log_iso(iso, log_iso_bits)
return f'iso8583 {r}'
def get_profile(iso):
p = FixLength(INVOICE_PROFILE)
try:
p.set_raw(iso.get_invoice_profile())
except BitNotSet:
return
return p
def get_nama_wp(iso, sppt):
if iso:
p = get_profile(iso)
if p:
return p['Nama']
return sppt.nm_wp_sppt
def get_user_id(iso):
try:
return iso.getBit(107)
except BitNotSet:
return
def data_pkeys(psppt):
return dict(
kd_propinsi=psppt.kd_propinsi, kd_dati2=psppt.kd_dati2,
kd_kecamatan=psppt.kd_kecamatan, kd_kelurahan=psppt.kd_kelurahan,
kd_blok=psppt.kd_blok, no_urut=psppt.no_urut,
kd_jns_op=psppt.kd_jns_op, thn_pajak_sppt=psppt.thn_pajak_sppt,
pembayaran_sppt_ke=psppt.pembayaran_sppt_ke)
class App(BaseApp): class App(BaseApp):
conf_name = 'pbb payment last date'
report_orm = Pbb
va_product_code = '02'
def __init__(self, argv): def __init__(self, argv):
super().__init__(argv) super().__init__(argv)
if not self.pid: if not self.pid:
...@@ -133,6 +58,13 @@ class App(BaseApp): ...@@ -133,6 +58,13 @@ class App(BaseApp):
self.Sppt = self.models.Sppt self.Sppt = self.models.Sppt
self.base_q_sppt = self.prod_session.query(self.Sppt) self.base_q_sppt = self.prod_session.query(self.Sppt)
self.nip_pospbb = self.conf['nip_pospbb'] self.nip_pospbb = self.conf['nip_pospbb']
if 'h2h_db_url' in self.conf:
factory = self.get_factory('h2h_db_url')
self.h2h_session = factory()
self.base_q_log = self.h2h_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
else:
self.h2h_session = None
def get_iso_reversal_orm(self): # Override def get_iso_reversal_orm(self): # Override
return self.iso_reversal_orm return self.iso_reversal_orm
...@@ -149,28 +81,13 @@ class App(BaseApp): ...@@ -149,28 +81,13 @@ class App(BaseApp):
thn_pajak_sppt=psppt.thn_pajak_sppt) thn_pajak_sppt=psppt.thn_pajak_sppt)
return q.first() return q.first()
def create_data(self, psppt, row_pay, iso): def get_iso_row(self, psppt):
sppt = self.get_sppt(psppt) iso_inq = self.iso_inquiry_orm
if not sppt: awal = psppt.tgl_rekam_byr_sppt.date()
msg = log_psppt_msg(psppt) akhir = awal + one_day
self.log.error(f'{msg} tidak ada di tabel sppt') q = self.get_iso_query(psppt)
raise SpptNotFound q = q.filter(iso_inq.tgl >= awal, iso_inq.tgl < akhir)
nama_wp = get_nama_wp(iso, sppt) return q.first()
bank_id = iso and iso.get_bank_id() or None
user_id = iso and get_user_id(iso) or None
discount = hasattr(psppt, 'discount') and psppt.discount or None
stan = iso and iso.get_stan() or None
ntb = iso and iso.get_ntb() or None
channel_kode = iso and iso.get_channel().strip() or \
(row_pay and row_pay.channel) or '0000'
return dict(
stan=stan, ntb=ntb, jml_sppt_yg_dibayar=psppt.jml_sppt_yg_dibayar,
denda_sppt=psppt.denda_sppt, discount=discount,
tgl_pembayaran_sppt=psppt.tgl_pembayaran_sppt.date(),
tgl_rekam_byr_sppt=psppt.tgl_rekam_byr_sppt,
nm_wp_sppt=nama_wp, channel_kode=channel_kode,
bank_id=bank_id, user_id=user_id,
pbb_yg_harus_dibayar_sppt=sppt.pbb_yg_harus_dibayar_sppt)
def get_iso_query(self, psppt): def get_iso_query(self, psppt):
iso_inq = self.iso_inquiry_orm iso_inq = self.iso_inquiry_orm
...@@ -186,33 +103,81 @@ class App(BaseApp): ...@@ -186,33 +103,81 @@ class App(BaseApp):
ke=psppt.pembayaran_sppt_ke) ke=psppt.pembayaran_sppt_ke)
return q.order_by(iso_inq.id.desc()) return q.order_by(iso_inq.id.desc())
def get_iso_row(self, psppt): def warning_date(self, psppt):
iso_inq = self.iso_inquiry_orm
awal = psppt.tgl_rekam_byr_sppt.date()
akhir = awal + one_day
q = self.get_iso_query(psppt)
q = q.filter(iso_inq.tgl >= awal, iso_inq.tgl < akhir)
return q.first()
def get_channel(self, psppt):
row_pay = self.get_iso_row(psppt)
if row_pay:
row_pay, row_inq = row_pay
iso = get_iso(row_pay.iso_request, Doc, self.option.debug)
info = get_channel_info_by_iso(iso)
return info['channel'], row_pay, row_inq, iso
elif psppt.nip_rekam_byr_sppt.strip() == self.nip_pospbb:
return 'POSPBB', None, None, None
q = self.get_iso_query(psppt) q = self.get_iso_query(psppt)
row = q.first() row = q.first()
if row: if row:
pay, inq = row pay, inq = row
msg = log_psppt_msg(psppt) msg = f'Invoice ID {self.invoice_id} berbeda tanggal dengan '\
msg = f'{msg}, iso8583 ada tapi tanggalnya beda yaitu {inq.tgl}' f'ISO8583 yaitu {psppt.tgl_rekam_byr_sppt.date()} vs '\
f'{inq.tgl}'
self.log.warning(msg) self.log.warning(msg)
return 'MANUAL', None, None, None
def get_report(self, psppt): def get_iso_v1(self, psppt):
row = self.get_iso_row(psppt)
if not row:
self.warning_date(psppt)
return
row_pay, row_inq = row
iso = get_iso(row_pay.iso_request, Doc, self.option.debug)
info = get_channel_info_by_iso(iso)
try:
user_id = iso.getBit(107)
except BitNotSet:
user_id = None
return iso.get_channel().strip(), info['channel'], iso.get_stan(), \
iso.get_ntb(), iso.get_bank_id(), user_id, row_inq.tgl
def get_iso_v2(self):
q = self.base_q_log.filter(func.trim(Log.bit_061) == 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_048.strip(), int(row.bit_032), row.bit_107
def create_data(self, psppt): # Override
self.invoice_id = get_id(psppt)
sppt = self.get_sppt(psppt)
if not sppt:
msg = f'Invoice ID {self.invoice_id} tidak ada di tabel sppt'
raise InvalidSource(msg)
source = self.get_iso_v2()
tgl_inquiry = user_id = stan = ntb = bank_id = None
if source:
channel_kode, channel_nama, stan, ntb, bank_id, user_id = source
else:
source = self.get_iso_v1(psppt)
if source:
channel_kode, channel_nama, stan, ntb, bank_id, user_id, \
tgl_inquiry = source
else:
channel_kode = '0000'
if psppt.nip_rekam_byr_sppt.strip() == self.nip_pospbb:
channel_nama = 'POSPBB'
else:
tgl = psppt.tgl_rekam_byr_sppt.date()
channel_nama = self.get_va_channel(tgl) or 'MANUAL'
discount = hasattr(psppt, 'discount') and psppt.discount or None
return dict(
kd_propinsi=psppt.kd_propinsi, kd_dati2=psppt.kd_dati2,
kd_kecamatan=psppt.kd_kecamatan, kd_kelurahan=psppt.kd_kelurahan,
kd_blok=psppt.kd_blok, no_urut=psppt.no_urut,
kd_jns_op=psppt.kd_jns_op, thn_pajak_sppt=psppt.thn_pajak_sppt,
pembayaran_sppt_ke=psppt.pembayaran_sppt_ke,
stan=stan, ntb=ntb, jml_sppt_yg_dibayar=psppt.jml_sppt_yg_dibayar,
denda_sppt=psppt.denda_sppt, discount=discount,
tgl_pembayaran_sppt=psppt.tgl_pembayaran_sppt.date(),
tgl_rekam_byr_sppt=psppt.tgl_rekam_byr_sppt,
nm_wp_sppt=sppt.nm_wp_sppt, channel_kode=channel_kode,
channel_nama=channel_nama, bank_id=bank_id, user_id=user_id,
pbb_yg_harus_dibayar_sppt=sppt.pbb_yg_harus_dibayar_sppt,
tgl_inquiry=tgl_inquiry)
def get_report(self, psppt): # Override
q = self.rpt_session.query(Pbb).filter_by( q = self.rpt_session.query(Pbb).filter_by(
kd_propinsi=psppt.kd_propinsi, kd_propinsi=psppt.kd_propinsi,
kd_dati2=psppt.kd_dati2, kd_dati2=psppt.kd_dati2,
...@@ -225,95 +190,23 @@ class App(BaseApp): ...@@ -225,95 +190,23 @@ class App(BaseApp):
pembayaran_sppt_ke=psppt.pembayaran_sppt_ke) pembayaran_sppt_ke=psppt.pembayaran_sppt_ke)
return q.first() return q.first()
def update_last(self): def get_last_time(self): # Override
self.last.nilai = dmyhms(self.last_psppt.tgl_rekam_byr_sppt) return dmyhms(self.last_pay.tgl_rekam_byr_sppt)
with transaction.manager:
self.rpt_session.add(self.last)
def log_msg(self, no, psppt, iso, channel_nama): def get_filter_query(self, q):
msg = log_psppt_msg(psppt) return q.filter(
msg = f'#{no}/{self.count} {msg}' self.Psppt.tgl_rekam_byr_sppt >= self.tgl_awal,
if iso: self.Psppt.tgl_rekam_byr_sppt < self.tgl_akhir + one_day)
s = log_iso_msg(iso)
msg = f'{msg}, {s}'
return f'{msg}, Channel {channel_nama}'
def update_from_date(self):
q = self.prod_session.query(self.Psppt).filter(
self.Psppt.tgl_rekam_byr_sppt > self.tgl_awal,
self.Psppt.tgl_rekam_byr_sppt < self.tgl_akhir)
q = q.order_by(self.Psppt.tgl_rekam_byr_sppt)
no = self.offset
found = False
for psppt in q.offset(self.offset).limit(row_limit):
found = True
no += 1
channel_nama, row_pay, row_inq, iso = self.get_channel(psppt)
d = dict(channel_nama=channel_nama)
if row_inq:
d['tgl_inquiry'] = row_inq.tgl
msg = self.log_msg(no, psppt, iso, channel_nama)
if not psppt.jml_sppt_yg_dibayar:
self.log.warning(
f'{msg}, field jml_sppt_yg_dibayar 0, abaikan')
continue
data = self.create_data(psppt, row_pay, iso)
d.update(data)
rpt = self.get_report(psppt)
if rpt:
method = 'UPDATE'
rpt.from_dict(d)
else:
method = 'INSERT'
pkeys = data_pkeys(psppt)
d.update(pkeys)
rpt = Pbb(**d)
self.log.info(f'{msg}, {method}')
with transaction.manager:
self.rpt_session.add(rpt)
self.last_psppt = psppt
self.offset += row_limit
return found
def get_count(self): def get_count(self): # Override
q = self.prod_session.query(func.count()).filter( q = self.prod_session.query(func.count())
self.Psppt.tgl_rekam_byr_sppt > self.tgl_awal, q = self.get_filter_query(q)
self.Psppt.tgl_rekam_byr_sppt < self.tgl_akhir)
return q.scalar() return q.scalar()
def run_payment(self): # Override def get_payment_query(self): # Override
self.last_psppt = None q = self.prod_session.query(self.Psppt)
self.last = None q = self.get_filter_query(q)
self.offset = 0 return q.order_by(self.Psppt.tgl_rekam_byr_sppt)
if self.option.update_from_id:
raise UpdateFromIdNotImplemented
if self.option.update_from_date:
t = self.option.update_from_date.split(',')
awal = datetime.strptime(t[0], '%d-%m-%Y')
self.tgl_awal = datetime(awal.year, awal.month, awal.day)
self.tgl_awal -= one_second
if t[1:]:
self.tgl_akhir = datetime.strptime(t[1], '%d-%m-%Y').date()
else:
self.tgl_akhir = date.today()
self.tgl_akhir += one_day
else:
self.last = self.get_last_id('pbb payment last date')
self.tgl_awal = self.last.as_datetime()
self.tgl_akhir = date.today() + one_day
self.count = self.get_count()
while True:
found = self.update_from_date()
if not found:
break
if self.last_psppt and self.last:
self.update_last()
def get_doc_for_reversal(self, row):
return Doc
def run_reversal(self): # Override
pass
def main(argv=sys.argv[1:]): def main(argv=sys.argv[1:]):
......
from datetime import ( from datetime import (
datetime, datetime,
date, date,
time as mktime, time,
) )
from decimal import Decimal
################# #################
# Compare value # # Compare value #
################# #################
MIDNIGHT_TIME = mktime(0, 0, 0) MIDNIGHT_TIME = time(0, 0, 0)
def split_time(t): def split_time(t) -> tuple:
if isinstance(t, datetime): if isinstance(t, datetime):
return t.date(), t.time() return t.date(), t.time()
return t, MIDNIGHT_TIME return t, MIDNIGHT_TIME
def is_same(a, b): def is_same(a, b) -> bool:
if a == b: if a == b:
return True return True
if not (isinstance(a, date) or isinstance(a, datetime)): if not (isinstance(a, date) or isinstance(a, datetime)):
...@@ -31,3 +32,59 @@ def is_same(a, b): ...@@ -31,3 +32,59 @@ def is_same(a, b):
if time_a == time_b: if time_a == time_b:
return True return True
return False return False
################
# Plain Object #
################
def date_str(v):
return f'{v.year}-{v.month:02}-{v.day:02}'
def time_str(v):
return f'{v.hour:02}:{v.minute:02}:{v.second:02}'
def datetime_str(v):
s_date = date_str(v)
s_time = time_str(v)
return f'{s_date} {s_time}'
def plain_value(v):
if isinstance(v, str):
return v
if isinstance(v, datetime):
return datetime_str(v)
if isinstance(v, date):
return date_str(v)
if isinstance(v, Decimal):
return float(v)
if isinstance(v, time):
return time_str(v)
return v
def plain_values(d):
r = dict()
for key in d:
v = d[key]
r[str(key)] = plain_value(v)
return r
def update(source: dict, target: dict):
target_update = dict()
log_msg = []
for field in target:
if field not in source:
continue
source_value = source[field]
target_value = target[field]
if not is_same(source_value, target_value):
target_update[field] = source_value
log_source_value = plain_value(source_value)
log_target_value = plain_value(target_value)
log_msg.append('{f} {t} to be {s}'.format(
f=field, t=[log_target_value], s=[log_source_value]))
return target_update, log_msg
import sys
from sqlalchemy import (
Column,
Integer,
)
import transaction
from opensipkd.waktu import (
dmyhms,
create_datetime,
date_from_str,
)
from sismiop.models.default import PembayaranSppt as BasePsppt
from sismiop.services.base import (
get_id,
)
from opensipkd.iso8583.bjb.scripts.common import get_module_object
from ..models import Pbb
from .common import (
get_iso,
get_keys,
BaseApp,
)
NIP_PENCATAT = '222222222'
CHANNEL_KODE = '7001'
CHANNEL_NAMA = 'VA'
LAST_CONF = 'va pbb last id'
ERR_NOT_FOUND = 'SPPT ID {invoice_id} tidak ada di sppt'
class PembayaranSppt(BasePsppt):
__table_args__ = dict(extend_existing=True)
id = Column(Integer, nullable=False)
user_id = Column(Integer)
def get_tgl_bayar(row):
t = row.tgl_rekam_byr_sppt
return create_datetime(t.year, t.month, t.day, t.hour, t.minute, t.second)
class App(BaseApp):
report_orm = Pbb
def __init__(self, argv):
super().__init__(argv)
if not self.pid:
return
self.models = get_module_object(self.conf['models'])
self.Sppt = self.models.Sppt
self.base_q_psppt = self.prod_session.query(PembayaranSppt).filter_by(
nip_rekam_byr_sppt=NIP_PENCATAT)
self.base_q_sppt = self.prod_session.query(self.Sppt)
def get_sppt(self, psppt):
q = self.base_q_sppt.filter_by(
kd_propinsi=psppt.kd_propinsi,
kd_dati2=psppt.kd_dati2,
kd_kecamatan=psppt.kd_kecamatan,
kd_kelurahan=psppt.kd_kelurahan,
kd_blok=psppt.kd_blok,
no_urut=psppt.no_urut,
kd_jns_op=psppt.kd_jns_op,
thn_pajak_sppt=psppt.thn_pajak_sppt)
return q.first()
def __get_query_psppt(self, last_id):
q = self.base_q_psppt.filter(PembayaranSppt.id > last_id)
return q.order_by(PembayaranSppt.id)
def __log_not_found(self, sppt_id):
msg = ERR_NOT_FOUND.format(invoice_id=sppt_id)
self.log.error(msg)
def __log_progress(self, row, sppt_id):
s_tgl = dmyhms(row.tgl_rekam_byr_sppt)
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {sppt_id}, '
f'pembayaran ke {row.pembayaran_sppt_ke}, ID {row.id}, '
f'jml_sppt_yg_dibayar {row.jml_sppt_yg_dibayar}')
def __run_payment(self):
last = self.get_last_id(LAST_CONF)
q_psppt = self.__get_query_psppt(last.as_int())
found = False
for psppt in q_psppt.limit(1000):
stan = psppt.tgl_pembayaran_sppt.strftime('%y%m%d')
ntb = f'{CHANNEL_NAMA}-{psppt.id}'
if self.get_report(stan, ntb):
continue
sppt_id = get_id(psppt)
sppt = self.get_sppt(psppt)
if not sppt:
self.__log_not_found(sppt_id)
continue
tgl_bayar = get_tgl_bayar(psppt)
user_id = str(psppt.user_id)
disc = psppt.discount or 0
self.__log_progress(psppt, sppt_id)
rpt = Pbb(
stan=stan, ntb=ntb, kd_propinsi=psppt.kd_propinsi,
kd_dati2=psppt.kd_dati2, kd_kecamatan=psppt.kd_kecamatan,
kd_kelurahan=psppt.kd_kelurahan, kd_blok=psppt.kd_blok,
no_urut=psppt.no_urut, kd_jns_op=psppt.kd_jns_op,
thn_pajak_sppt=psppt.thn_pajak_sppt,
pembayaran_sppt_ke=psppt.pembayaran_sppt_ke,
jml_sppt_yg_dibayar=psppt.jml_sppt_yg_dibayar,
denda_sppt=psppt.denda_sppt,
tgl_pembayaran_sppt=psppt.tgl_pembayaran_sppt,
tgl_rekam_byr_sppt=psppt.tgl_rekam_byr_sppt,
nm_wp_sppt=sppt.nm_wp_sppt, channel_kode=CHANNEL_KODE,
channel_nama=CHANNEL_NAMA, user_id=user_id,
pbb_yg_harus_dibayar_sppt=sppt.pbb_yg_harus_dibayar_sppt,
tgl_inquiry=tgl_bayar, discount=disc)
last.nilai = str(psppt.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
found = True
return found
def __update_from_id(self):
q_psppt = self.__get_query_psppt(self.last_id)
found = False
for psppt in q_psppt.limit(1000):
sppt_id = get_id(psppt)
sppt = self.get_sppt(psppt)
if not sppt:
self.__log_not_found(sppt_id)
continue
stan = psppt.tgl_pembayaran_sppt.strftime('%y%m%d')
ntb = f'{CHANNEL_NAMA}-{psppt.id}'
tgl_bayar = get_tgl_bayar(psppt)
user_id = str(psppt.user_id)
disc = psppt.discount or 0
rpt = self.get_report(stan, ntb)
if not rpt:
rpt = Pbb()
self.__log_progress(psppt, sppt_id)
d = dict(
stan=stan, ntb=ntb, kd_propinsi=psppt.kd_propinsi,
kd_dati2=psppt.kd_dati2, kd_kecamatan=psppt.kd_kecamatan,
kd_kelurahan=psppt.kd_kelurahan, kd_blok=psppt.kd_blok,
no_urut=psppt.no_urut, kd_jns_op=psppt.kd_jns_op,
thn_pajak_sppt=psppt.thn_pajak_sppt,
pembayaran_sppt_ke=psppt.pembayaran_sppt_ke,
jml_sppt_yg_dibayar=psppt.jml_sppt_yg_dibayar,
denda_sppt=psppt.denda_sppt,
tgl_pembayaran_sppt=psppt.tgl_pembayaran_sppt,
tgl_rekam_byr_sppt=psppt.tgl_rekam_byr_sppt,
nm_wp_sppt=sppt.nm_wp_sppt, channel_kode=CHANNEL_KODE,
channel_nama=CHANNEL_NAMA, user_id=user_id,
pbb_yg_harus_dibayar_sppt=sppt.pbb_yg_harus_dibayar_sppt,
tgl_inquiry=tgl_bayar, discount=disc)
rpt.from_dict(d)
with transaction.manager:
self.rpt_session.add(rpt)
found = True
self.last_id = psppt.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(PembayaranSppt).filter(
PembayaranSppt.tgl_rekam_byr_sppt >= tgl).order_by(
PembayaranSppt.tgl_rekam_byr_sppt)
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 main(argv=sys.argv[1:]):
app = App(argv)
app.run()
import sys import sys
from datetime import datetime from datetime import (
date,
datetime,
)
from sqlalchemy import func
from sqlalchemy.exc import ProgrammingError from sqlalchemy.exc import ProgrammingError
import transaction import transaction
from opensipkd.waktu import dmyhms from opensipkd.waktu import dmyhms
...@@ -22,6 +26,7 @@ from .common import ( ...@@ -22,6 +26,7 @@ from .common import (
init_db as base_init_db, init_db as base_init_db,
BIT_18_NAMES, BIT_18_NAMES,
get_channel_name_by_row, get_channel_name_by_row,
one_day,
) )
...@@ -30,12 +35,16 @@ class AlternativeLog(Base, LogMixin): ...@@ -30,12 +35,16 @@ class AlternativeLog(Base, LogMixin):
class App(BaseApp): class App(BaseApp):
conf_name = 'webr payment last date'
report_orm = Webr
product_code = '30'
def __init__(self, argv): def __init__(self, argv):
super().__init__(argv) super().__init__(argv)
if not self.pid: if not self.pid:
return return
self.base_q_pay = self.prod_session.query(Payment, Invoice).filter( self.base_q_pay = self.prod_session.query(Payment)
Payment.ar_invoice_id == Invoice.id) self.base_q_inv = self.prod_session.query(Invoice)
self.base_q_iso = self.prod_session.query(Log) self.base_q_iso = self.prod_session.query(Log)
try: try:
self.base_q_iso.first() self.base_q_iso.first()
...@@ -47,82 +56,49 @@ class App(BaseApp): ...@@ -47,82 +56,49 @@ class App(BaseApp):
self.base_q_iso = self.base_q_iso.filter_by( self.base_q_iso = self.base_q_iso.filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00') mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
def get_channel(self, pay, inv): def get_iso(self, inv):
if not pay.bank_id: q = self.base_q_iso.filter(func.trim(self.IsoLog.bit_061) == inv.kode)
return '0000', 'MANUAL', None return q.first()
nomor_bayar = inv.kode
q = self.base_q_iso.filter(self.IsoLog.bit_061.like(f'{nomor_bayar}%')) def create_data(self, pay): # Override
iso = q.first() q = self.base_q_inv.filter_by(id=pay.ar_invoice_id)
if not iso: inv = q.first()
name = BIT_18_NAMES[str(pay.channel_id)] self.invoice_id = inv.kode
return pay.channel_id, name, None iso = self.get_iso(pay)
name = get_channel_name_by_row(iso) if iso:
return iso.bit_018, name, iso channel_id = iso.bit_018.strip()
channel_name = get_channel_name_by_row(iso)
elif pay.bank_id:
channel_id = str(pay.channel_id)
channel_name = BIT_18_NAMES[channel_id]
else:
channel_id = '0000'
channel_name = self.get_va_channel(pay.created.date()) or 'MANUAL'
stan = iso and iso.bit_011 or None
ntb = pay.ntb and pay.ntb.strip() or None
return dict(
id=pay.id, stan=stan, ntb=ntb, tgl=pay.created.date(),
jam=pay.created.time(), nomor_bayar=self.invoice_id,
nama_wp=inv.subjek_nama, pokok=inv.jumlah-inv.bunga,
denda=pay.bunga, jml_bayar=pay.bayar, channel_id=channel_id,
channel_name=channel_name)
def update_last(self, pay): def get_last_time(self): # Override
self.last_id = pay.id return dmyhms(self.last_pay.created)
self.last.nilai = str(pay.id)
with transaction.manager:
self.rpt_session.add(self.last)
def update_from_id(self): def get_filter_query(self, q):
q_pay = self.base_q_pay.filter(Payment.id > self.last_id) return q.filter(
no = 0 Payment.created >= self.tgl_awal,
for pay, inv in q_pay.order_by(Payment.id).limit(1000): Payment.created < self.tgl_akhir + one_day)
no += 1
channel_id, channel_name, iso = self.get_channel(pay, inv)
nomor_bayar = inv.kode
tgl_bayar = pay.created.date()
s_tgl = dmyhms(pay.created)
stan = iso and iso.bit_011 or None
ntb = pay.ntb and pay.ntb.strip() or None
msg = f'#{no} ID {pay.id}, Tgl bayar {s_tgl}, '\
f'Nomor bayar {nomor_bayar}, Channel {channel_name}'
if iso:
msg = f'{msg}, STAN {stan}, NTB {ntb}'
if not pay.bayar:
self.log.warning(f'{msg}, field bayar 0, abaikan')
self.last and self.update_last(pay)
continue
self.log.info(msg)
d = dict(
stan=stan, ntb=ntb, tgl=tgl_bayar, jam=pay.created.time(),
nomor_bayar=nomor_bayar, nama_wp=inv.subjek_nama,
pokok=inv.jumlah-inv.bunga, denda=pay.bunga,
jml_bayar=pay.bayar, channel_id=channel_id,
channel_name=channel_name)
q = self.rpt_session.query(Webr).filter_by(id=pay.id)
rpt = q.first()
if rpt:
rpt.from_dict(d)
else:
d['id'] = pay.id
rpt = Webr(**d)
self.last_id = pay.id
with transaction.manager:
self.rpt_session.add(rpt)
if self.last:
self.last.nilai = str(pay.id)
self.rpt_session.add(last)
return no
def run_payment(self): # Override def get_count(self): # Override
self.last = None q = self.prod_session.query(func.count())
if self.option.update_from_id: q = self.get_filter_query(q)
self.last_id = self.option.update_from_id return q.scalar()
elif self.option.update_from_date:
tgl = datetime.strptime(self.option.update_from_date, '%d-%m-%Y') def get_payment_query(self): # Override
q = self.prod_session.query(Payment).filter( q = self.get_filter_query(self.base_q_pay)
Payment.created >= tgl).order_by(Payment.id) return q.order_by(Payment.created)
row = q.first()
self.last_id = row.id - 1
else:
self.last = self.get_last_id('webr payment last id')
self.last_id = self.last.as_int()
while True:
found = self.update_from_id()
if not found:
break
def main(argv=sys.argv[1:]): def main(argv=sys.argv[1:]):
......
import sys
from sqlalchemy.exc import ProgrammingError
import transaction
from opensipkd.waktu import dmyhms
from opensipkd.iso8583.bjb.webr.structure import PAYMENT_CODE
from opensipkd.iso8583.bjb.webr.models import (
LogMixin,
Log,
)
from iso8583_web.models.meta import Base as BaseConf
from ..models import (
Base,
Webr,
)
from .common import (
App2 as BaseApp,
init_db as base_init_db,
)
ERR_NOT_FOUND = 'Tgl {tgl_bayar} nomor bayar {invoice_id} tidak ada'
class AlternativeLog(Base, LogMixin):
__table_args__ = dict(schema='webr')
class App(BaseApp):
field_invoice_id = 'bit_061'
field_ntb = 'bit_048'
report_orm = Webr
def __init__(self, argv):
super().__init__(argv)
if not self.pid:
return
self.base_q_iso_resp = self.prod_session.query(Log)
self.log_orm = Log
try:
self.base_q_iso_resp.first()
except ProgrammingError:
self.prod_session.rollback()
self.base_q_iso_resp = self.prod_session.query(AlternativeLog)
self.log_orm = AlternativeLog
self.base_q_iso_resp = self.base_q_iso_resp.filter_by(
mti='0210', bit_003=PAYMENT_CODE)
def is_iso_resp_ok(self, iso_req):
q = self.base_q_iso_resp.filter_by(
bit_011=iso_req.bit_011, bit_048=iso_req.bit_048)
iso_resp = q.order_by(Log.id.desc()).first()
return iso_resp and iso_resp.bit_039 == '00'
def run_payment(self):
last = self.get_last_id('webr2 payment last id')
q_iso_req = self.prod_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE).filter(
Log.id > last.as_int())
for iso_req in q_iso_req.order_by(Log.id):
if self.get_report(iso_req):
continue
if not self.is_iso_resp_ok(iso_req):
continue
d = self.get_keys(iso_req)
tgl_bayar = iso_req.created.date()
s_tgl = dmyhms(iso_req.created)
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
rpt = Webr(
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar,
jam=iso_req.created.time(), payment_id=iso_req.id,
nomor_bayar=d['nomor_bayar'],
nama_wp=iso_req.bit_062_data['Nama Penyetor'],
pokok=iso_req.bit_004,
denda=0, jml_bayar=iso_req.bit_004,
channel_id=iso_req.bit_018.strip(),
channel_name=d['channel'])
last.nilai = str(iso_req.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
def get_log_orm(self): # Override
return self.log_orm
def run_reversal(self): # Override
super().run_reversal('webr2 reversal last id')
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)
[main] [main]
models = sismiop.models.default models = sismiop.models.default
db_url = postgresql://user:pass@localhost/db db_url = postgresql://user:pass@localhost/db
#h2h_db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/pbb-report.pid pid_file = /home/sugiana/tmp/pbb-report.pid
log_file = /home/sugiana/log/pbb-report.log log_file = /home/sugiana/log/pbb-report.log
......
...@@ -37,15 +37,11 @@ setup( ...@@ -37,15 +37,11 @@ setup(
'payment_report_init_db = payment_report.scripts.common:init_db', 'payment_report_init_db = payment_report.scripts.common:init_db',
'pbb_report = payment_report.scripts.pbb:main', 'pbb_report = payment_report.scripts.pbb:main',
'pbb_json_report = payment_report.scripts.pbb_json:main', 'pbb_json_report = payment_report.scripts.pbb_json:main',
'va_pbb_report = payment_report.scripts.va_pbb:main',
'bphtb_report = payment_report.scripts.bphtb:main', 'bphtb_report = payment_report.scripts.bphtb:main',
'bphtb_json_report = payment_report.scripts.bphtb_json:main', 'bphtb_json_report = payment_report.scripts.bphtb_json:main',
'bphtb2_report = payment_report.scripts.bphtb2:main',
'pad_report = payment_report.scripts.pad:main', 'pad_report = payment_report.scripts.pad:main',
'pad_json_report = payment_report.scripts.pad_json:main', 'pad_json_report = payment_report.scripts.pad_json:main',
'pad2_report = payment_report.scripts.pad2:main',
'webr_report = payment_report.scripts.webr:main', 'webr_report = payment_report.scripts.webr:main',
'webr2_report = payment_report.scripts.webr2:main',
], ],
} }
) )
[main] [main]
db_url = postgresql://user:pass@localhost/db db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/webr-report.pid pid_file = /home/sugiana/tmp/webr-report.pid
log_file = /home/sugiana/log/webr-report.log log_file = /home/sugiana/log/webr-report.log
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!