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
bukan dari tabel ISO8583 karena sudah memperhatikan channel MANUAL (input
manual pembayaran)
- Memahami channel VA dan QRIS
[main]
models = opensipkd.bphtb.models.default
db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/bphtb-report.pid
log_file = /home/sugiana/log/bphtb-report.log
[main]
models = opensipkd.pad.models.default
db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/pad-report.pid
log_file = /home/sugiana/log/pad-report.log
......@@ -16,6 +16,12 @@ Base = declarative_base()
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):
for column in self.__table__.columns:
if column.name in values:
......@@ -24,25 +30,24 @@ class Common:
class Pad(Base, Common):
__tablename__ = 'pad_report'
# pad.pad_sspd.id
id = Column(Integer, primary_key=True)
# Bit 11
stan = Column(String(6), nullable=False)
stan = Column(String(6))
# Bit 48
ntb = Column(String(32), nullable=False)
ntb = Column(String(32))
# pad.pad_sspd.create_date / log_iso.created
tgl = Column(Date, nullable=False)
# pad.pad_sspd.sspdjam / log_iso.created
jam = Column(Time, nullable=False)
# pad.pad_sspd.id
sspd_id = Column(Integer, nullable=False)
# Bit 61
nomor_bayar = Column(String(16), nullable=False)
# pad.pad_usaha.usahanm
jenis_pajak = Column(String(32), nullable=False)
jenis_pajak = Column(String(64), nullable=False)
# pad.pad_pajak.masapajak
masa_pajak = Column(Integer, nullable=False)
# pad.pad_customer.npwpd
npwpd = Column(String(17), nullable=False)
npwpd = Column(String(17))
# pad.pad_customer.customernm
nama_wp = Column(String(150), nullable=False)
# pad.pad_sspd.jml_bayar - pad.pad_sspd.denda
......@@ -59,9 +64,6 @@ class Pad(Base, Common):
channel_name = Column(String(32), nullable=False)
# pad_reversal.tgl
tgl_batal = Column(DateTime(timezone=True))
__table_args__ = (
UniqueConstraint('stan', 'ntb'),
)
class Webr(Base, Common):
......@@ -90,17 +92,17 @@ class Webr(Base, Common):
channel_id = Column(String(4), nullable=False)
# Bit 41 / 42 / 43
channel_name = Column(String(32), nullable=False)
# pad_reversal.tgl
tgl_batal = Column(DateTime(timezone=True))
class Bphtb(Base, Common):
__tablename__ = 'bphtb_report'
# bphtb.bphtb_bank.id
id = Column(Integer, primary_key=True)
# Bit 11
stan = Column(String(6), nullable=False)
stan = Column(String(6))
# Bit 58
ntb = Column(String(32), nullable=False)
ntb = Column(String(32))
# bphtb.bphtb_bank.tanggal
tgl = Column(Date, nullable=False)
# bphtb.bphtb_bank.jam
......@@ -133,9 +135,6 @@ class Bphtb(Base, Common):
channel_nama = Column(String(32), nullable=False)
# bphtb.bphtb_reversal.tgl
tgl_batal = Column(DateTime(timezone=True))
__table_args__ = (
UniqueConstraint('stan', 'ntb'),
)
class Pbb(Base, Common):
......
......@@ -6,8 +6,9 @@ from sqlalchemy import (
String,
Date,
ForeignKey,
func,
)
import transaction
from opensipkd.string import FixLength
from opensipkd.waktu import dmyhms
from opensipkd.bphtb.models.default import (
Payment,
......@@ -15,17 +16,23 @@ from opensipkd.bphtb.models.default import (
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_keys,
App as BaseApp,
get_channel_name_by_row,
get_channel_info_by_iso,
BaseApp,
init_db as base_init_db,
one_day,
InvalidSource,
)
......@@ -47,70 +54,105 @@ class IsoPayment(Base):
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
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_inv = self.prod_session.query(
Invoice, Customer, Perolehan).filter(
Invoice.ppat_id == Customer.id,
Invoice.perolehan_id == Perolehan.id)
def run_payment(self): # Override
last = self.get_last_id('bphtb payment last id')
q_iso = self.prod_session.query(IsoPayment, Payment).filter(
IsoPayment.id == Payment.id,
IsoPayment.id > last.as_int())
for row_iso, row_pay in q_iso.order_by(IsoPayment.id):
if row_iso.iso_request[0] == '{':
last.nilai = str(row_iso.id)
with transaction.manager:
self.rpt_session.add(last)
continue
iso = get_iso(row_iso.iso_request, Doc, self.option.debug)
if self.get_report(iso):
continue
tgl_bayar = row_iso.tgl.date()
q_inv = self.base_q_inv.filter(Invoice.id == row_pay.sspd_id)
inv, ppat, perolehan = q_inv.first()
d = get_keys(iso)
s_tgl = dmyhms(row_iso.tgl)
self.log.info(
f'Tgl bayar {s_tgl}, Nomor bayar {d["nomor_bayar"]}, '
f'STAN {d["stan"]}, NTB {d["ntb"]}, Channel {d["channel"]}')
rpt = Bphtb(
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar,
jam=row_iso.tgl.time(),
invoice_id=iso.get_invoice_id().strip(),
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=iso.get_channel().strip(),
channel_nama=d['channel'])
last.nilai = str(row_iso.id)
with transaction.manager:
self.rpt_session.add(rpt)
self.rpt_session.add(last)
def get_iso_reversal_orm(self): # Override
return IsoReversal
def run_reversal(self): # Override
super().run_reversal('bphtb reversal last date')
self.base_q_inv = self.prod_session.query(Invoice)
self.base_q_cust = self.prod_session.query(Customer)
self.base_q_perolehan = self.prod_session.query(Perolehan)
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(
Payment.tanggal >= self.tgl_awal.date(),
Payment.jam >= self.tgl_awal.time(),
Payment.tanggal < self.tgl_akhir + one_day)
def get_count(self) -> int: # 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.tanggal, 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['bit_018'], info['channel'], iso.get_stan(), iso.get_ntb()
def get_iso_v2(self):
q = self.prod_session.query(Log).filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
q = q.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
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:]):
......
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)
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 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
pad2 payment last id,0,log_iso.id terakhir yang diproses
pad2 reversal last id,0,log_iso.id 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
webr payment last date,1-1-2000 00:00:00,webr.ar_payment.created terakhir yang diproses
bphtb payment last date,01-01-2000 00:00:00,bphtb.bphtb_bank.tanggal 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
from datetime import timedelta
import transaction
from opensipkd.waktu import (
dmyhms,
date_from_str,
from datetime import (
date,
datetime,
)
from sqlalchemy import func
from opensipkd.string import FixLength
from opensipkd.waktu import dmyhms
from opensipkd.pad.models.default import (
Payment,
IsoPayment,
IsoReversal,
)
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.models import Log
from opensipkd.iso8583.multi.doc import Doc as MultiDoc
from ..models import (
Base,
......@@ -18,22 +21,25 @@ from ..models import (
)
from .common import (
get_iso,
get_keys,
App as BaseApp,
get_channel_info_by_iso,
get_channel_name_by_row,
BaseApp,
init_db as base_init_db,
one_day,
)
BankHandlers = {
8: MultiDoc,
14: MultiDoc,
110: BjbDoc,
700: MultiDoc}
ERR_NOT_FOUND = 'Tgl {tgl_bayar} pad.pad_sspd.spt_id {invoice_id} tidak ada'
class App(BaseApp):
conf_name = 'pad payment last date'
report_orm = Pad
va_product_code = '10'
def __init__(self, argv):
super().__init__(argv)
......@@ -53,132 +59,83 @@ class App(BaseApp):
Invoice.customer_usaha_id == CustomerUsaha.id,
CustomerUsaha.customer_id == Customer.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()
Payment = self.models.Payment
q_pay = self.base_q_pay.filter_by(spt_id=row.invoice_id).filter(
Payment.create_date >= tgl_bayar,
Payment.create_date < tgl_bayar + timedelta(1))
q_pay = q_pay.order_by(Payment.id.desc())
return q_pay.first()
def get_pay_date(self): # Override
return self.last_pay.sspdtgl.date()
def __get_query_iso(self, last_id):
q_iso = self.base_q_iso.filter(IsoPayment.id > last_id)
return q_iso.order_by(IsoPayment.id)
def get_last_time(self): # Override
return dmyhms(self.last_pay.sspdtgl)
def __create_data(self, row, pay, iso, d, tgl_bayar):
Invoice = self.models.Invoice
q_inv = self.base_q_inv.filter(Invoice.id == pay.spt_id)
inv, pajak, cust, usaha = q_inv.first()
return dict(
stan=d['stan'], ntb=d['ntb'], tgl=tgl_bayar,
jam=row.tgl.time(), sspd_id=pay.id,
nomor_bayar=iso.get_invoice_id().strip(),
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.get_channel().strip(),
channel_name=d['channel'], bank_id=iso.get_bank_id())
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)
def get_filter_query(self, q):
return q.filter(
Payment.sspdtgl >= self.tgl_awal,
Payment.sspdtgl < self.tgl_akhir + one_day)
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)
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)
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()
self.last_id = row.id - 1
func = self.__update_from_id
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, pay): # Override
Invoice = self.models.Invoice
q_inv = self.base_q_inv.filter(Invoice.id == pay.spt_id)
inv, pajak, cust, usaha = q_inv.first()
invoice_id = FixLength(self.service.INVOICE_ID)
invoice_id['Tahun'] = inv.tahun
invoice_id['SptNo'] = inv.sptno
prefix = getattr(self.service, 'PREFIX')
if prefix:
invoice_id['Prefix'] = prefix
self.invoice_id = invoice_id.get_raw()
source = self.get_iso_v2()
if source:
channel_id, channel_name, stan, ntb, bank_id = source
else:
func = self.__run_payment
while True:
found = func()
if not found:
break
def get_iso_reversal_orm(self): # Override
return IsoReversal
def get_doc_for_reversal(self, row): # Override
q = self.prod_session.query(IsoPayment).filter_by(id=row.id)
iso_pay = q.first()
return BankHandlers[iso_pay.bank_id]
def run_reversal(self): # Override
super().run_reversal('pad reversal last date')
source = self.get_iso_v1(pay)
if source:
channel_id, channel_name, stan, ntb, bank_id = source
else:
stan = ntb = bank_id = None
channel_id = '0000'
tgl = pay.sspdtgl.date()
channel_name = self.get_va_channel(tgl) or 'MANUAL'
return dict(
id=pay.id, stan=stan, ntb=ntb, tgl=pay.sspdtgl.date(),
jam=pay.sspdtgl.time(), nomor_bayar=invoice_id.get_raw(),
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=channel_id,
channel_name=channel_name, bank_id=bank_id)
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)
from datetime import (
datetime,
date,
time as mktime,
time,
)
from decimal import Decimal
#################
# 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):
return t.date(), t.time()
return t, MIDNIGHT_TIME
def is_same(a, b):
def is_same(a, b) -> bool:
if a == b:
return True
if not (isinstance(a, date) or isinstance(a, datetime)):
......@@ -31,3 +32,59 @@ def is_same(a, b):
if time_a == time_b:
return True
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
from datetime import datetime
from datetime import (
date,
datetime,
)
from sqlalchemy import func
from sqlalchemy.exc import ProgrammingError
import transaction
from opensipkd.waktu import dmyhms
......@@ -22,6 +26,7 @@ from .common import (
init_db as base_init_db,
BIT_18_NAMES,
get_channel_name_by_row,
one_day,
)
......@@ -30,12 +35,16 @@ class AlternativeLog(Base, LogMixin):
class App(BaseApp):
conf_name = 'webr payment last date'
report_orm = Webr
product_code = '30'
def __init__(self, argv):
super().__init__(argv)
if not self.pid:
return
self.base_q_pay = self.prod_session.query(Payment, Invoice).filter(
Payment.ar_invoice_id == Invoice.id)
self.base_q_pay = self.prod_session.query(Payment)
self.base_q_inv = self.prod_session.query(Invoice)
self.base_q_iso = self.prod_session.query(Log)
try:
self.base_q_iso.first()
......@@ -47,82 +56,49 @@ class App(BaseApp):
self.base_q_iso = self.base_q_iso.filter_by(
mti='0210', bit_003=PAYMENT_CODE, bit_039='00')
def get_channel(self, pay, inv):
if not pay.bank_id:
return '0000', 'MANUAL', None
nomor_bayar = inv.kode
q = self.base_q_iso.filter(self.IsoLog.bit_061.like(f'{nomor_bayar}%'))
iso = q.first()
if not iso:
name = BIT_18_NAMES[str(pay.channel_id)]
return pay.channel_id, name, None
name = get_channel_name_by_row(iso)
return iso.bit_018, name, iso
def update_last(self, pay):
self.last_id = pay.id
self.last.nilai = str(pay.id)
with transaction.manager:
self.rpt_session.add(self.last)
def get_iso(self, inv):
q = self.base_q_iso.filter(func.trim(self.IsoLog.bit_061) == inv.kode)
return q.first()
def update_from_id(self):
q_pay = self.base_q_pay.filter(Payment.id > self.last_id)
no = 0
for pay, inv in q_pay.order_by(Payment.id).limit(1000):
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)
def create_data(self, pay): # Override
q = self.base_q_inv.filter_by(id=pay.ar_invoice_id)
inv = q.first()
self.invoice_id = inv.kode
iso = self.get_iso(pay)
if 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
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,
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)
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
self.last = None
if self.option.update_from_id:
self.last_id = self.option.update_from_id
elif self.option.update_from_date:
tgl = datetime.strptime(self.option.update_from_date, '%d-%m-%Y')
q = self.prod_session.query(Payment).filter(
Payment.created >= tgl).order_by(Payment.id)
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 get_last_time(self): # Override
return dmyhms(self.last_pay.created)
def get_filter_query(self, q):
return q.filter(
Payment.created >= self.tgl_awal,
Payment.created < self.tgl_akhir + one_day)
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.get_filter_query(self.base_q_pay)
return q.order_by(Payment.created)
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]
models = sismiop.models.default
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
pid_file = /home/sugiana/tmp/pbb-report.pid
log_file = /home/sugiana/log/pbb-report.log
......
......@@ -37,15 +37,11 @@ setup(
'payment_report_init_db = payment_report.scripts.common:init_db',
'pbb_report = payment_report.scripts.pbb: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_json_report = payment_report.scripts.bphtb_json:main',
'bphtb2_report = payment_report.scripts.bphtb2:main',
'pad_report = payment_report.scripts.pad:main',
'pad_json_report = payment_report.scripts.pad_json:main',
'pad2_report = payment_report.scripts.pad2:main',
'webr_report = payment_report.scripts.webr:main',
'webr2_report = payment_report.scripts.webr2:main',
],
}
)
[main]
db_url = postgresql://user:pass@localhost/db
#va_db_url = postgresql://user:pass@localhost/db
report_db_url = postgresql://user:pass@localhost/db
pid_file = /home/sugiana/tmp/webr-report.pid
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!