Commit dabea098 by Owo Sugiana

Kali pertama

0 parents
dist
build
*egg-info
test-*.ini
__pycache__
.idea
0.1 2022-9-23
-------------
- Kali pertama
Modul BNI untuk ISO8583
=======================
Ini adalah modul untuk `iso8583-web <https://git.opensipkd.com/sugiana/iso8583-web>`_
yang berkaitan dengan Bank BNI.
Pemasangan
----------
Ikutilah petunjuk pemasangan `opensipkd-iso8583-bjb <https://git.opensipkd.com/sugiana/opensipkd-iso8583-bjb>`_.
Pada file konfigurasi ubah menjadi::
streamer = bni
module = opensipkd.iso8583.bni.pbb
Untuk mencobanya ikuti lagi petunjuk pada `opensipkd-iso8583-bjb <https://git.opensipkd.com/sugiana/opensipkd-iso8583-bjb>`_
namun dengan mengganti ``env/bin/iso8583_bjb_bphtb_inquiry`` menjadi ``env/bin/iso8583_bni_pbb_inquiry``.
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
from opensipkd.iso8583.bjb.pbb.init import init
from .doc import Doc
from .job import Job
from opensipkd.string import FixLength
from opensipkd.iso8583.network.doc import Doc as NetworkDoc
from opensipkd.iso8583.bjb.pbb.majalengka import Doc as BaseDoc
from opensipkd.iso8583.bjb.structure import (
ERR_NOT_AVAILABLE,
ERR_ALREADY_PAID,
ERR_INSUFFICIENT_FUND,
ERR_PAYMENT_NOT_FOUND,
ERR_INVOICE_OPEN,
)
from sismiop.services.base import get_nop
from .structure import (
TRANSACTION_BITS,
INQUIRY_CODE,
PAYMENT_CODE,
INVOICE_PROFILE,
RC_ALREADY_PAID,
RC_NOT_AVAILABLE,
RC_PAYMENT_NOT_FOUND,
RC_ALREADY_CANCELLED,
RC_OTHER,
)
from .models import Log
class Doc(BaseDoc):
def get_bit_definition(self): # Override
return TRANSACTION_BITS
def get_inquiry_code(self): # Override
return INQUIRY_CODE
def get_payment_code(self): # Override
return PAYMENT_CODE
def get_log_model(self): # Overrride
return Log
def get_inquiry_bits(self): # Override
return [4, 48]
def get_payment_bits(self): # Override
return [3, 4, 11, 37, 48]
def set_invoice_id(self, value):
self.setBit(48, value)
def get_invoice_id(self):
return self.getBit(48).strip().lstrip('0')
def get_transaction_time(self):
raw = self.getBit(7)
self.transaction_time.set_raw(raw)
return self.transaction_time.get_value()
def getBit(self, bit): # Override
if bit in (18, 41, 42, 43):
return
return super().getBit(bit)
def set_invoice_profile(self, raw):
self.setBit(48, raw)
def set_ntb(self, v): # Override
self.setBit(37, v)
def get_ntb(self): # Override
return self.get_value(37)
def set_ntp(self, v): # Override
self.invoice_profile['NTP'] = v
def get_ntp(self): # Override
return self.invoice_profile['NTP']
def copy_inquiry_bits(self):
self.copy([3, 7, 11, 32, 37, 48])
def set_all_invoice_profile(self, inq): # Override
p = FixLength(INVOICE_PROFILE)
p.from_dict({
'Invoice ID': self.get_invoice_id(),
'Nama': inq.get_nama_wp(),
'Nama Kecamatan': inq.get_kecamatan_op(),
'Nama Kelurahan': inq.get_kelurahan_op(),
'Tagihan': inq.tagihan,
'Denda': inq.denda,
'Total Bayar': inq.tagihan + inq.denda})
self.invoice_profile = p
self.set_invoice_profile_bit()
DBSession = self.get_db_session()
inv = inq.invoice
nop = get_nop(inv)
t_inq_id = self.inquiry_sequence.execute(DBSession.bind)
t_inq = self.iso_inquiry_model(
id=t_inq_id, nop=nop, propinsi=inv.kd_propinsi,
kabupaten=inv.kd_dati2, kecamatan=inv.kd_kecamatan,
kelurahan=inv.kd_kelurahan, blok=inv.kd_blok,
urut=inv.no_urut, jenis=inv.kd_jns_op,
tahun=inv.thn_pajak_sppt, tgl=inq.tgl_bayar,
tagihan=inq.tagihan, denda=inq.denda,
persen_denda=inq.persen_denda,
jatuh_tempo=inq.get_jatuh_tempo(),
bulan_tunggakan=inq.bln_tunggakan,
pengirim=self.get_bank_id())
DBSession.add(t_inq)
def set_invoice_profile_bit(self):
self.setBit(48, self.invoice_profile.get_raw())
self.long_bits[48] = self.invoice_profile.to_dict()
def do_payment(self, inq): # Override
pay = super().do_payment(inq)
self.set_invoice_profile_bit()
return pay
def set_inquiry_request(self, tgl_bayar=None): # Override
NetworkDoc.set_inquiry_request(self)
self.set_bank_id('009')
def set_payment_request(self, tgl_bayar=None): # Override
NetworkDoc.set_payment_request(self)
self.set_bank_id('009')
if not tgl_bayar:
tgl_bayar = datetime.now()
inq = self.get_inquiry_response()
if inq:
self.set_bits_from_inquiry(inq)
def ack_not_found(self): # Override
msg = ERR_NOT_FOUND.format(invoice_id=self.get_invoice_id())
self.ack(RC_NOT_AVAILABLE, msg)
def ack_not_available(self): # Override
msg = ERR_NOT_AVAILABLE.format(invoice_id=self.get_invoice_id())
self.ack(RC_NOT_AVAILABLE, msg)
def ack_already_paid(self): # Override
msg = ERR_ALREADY_PAID.format(invoice_id=self.get_invoice_id())
self.ack(RC_ALREADY_PAID, msg)
def ack_insufficient_fund(self, total): # Override
msg = ERR_INSUFFICIENT_FUND.format(
invoice_id=self.get_invoice_id(),
bayar=self.from_iso.get_amount(),
tagihan=total)
self.ack(RC_INSUFFICIENT_FUND, msg)
def ack_payment_not_found(self): # Override
msg = ERR_PAYMENT_NOT_FOUND.format(invoice_id=self.get_invoice_id())
self.ack(RC_PAYMENT_NOT_FOUND, msg)
def ack_invoice_open(self): # Override
msg = ERR_INVOICE_OPEN.format(invoice_id=self.get_invoice_id())
self.ack(RC_ALREADY_CANCELLED, msg)
def ack_other(self, msg): # Override
self.ack(RC_OTHER, msg)
from opensipkd.iso8583.bjb.pbb.majalengka import Job as BaseJob
from .doc import Doc
class Job(BaseJob):
def get_iso_class(self):
return Doc
from sqlalchemy import (
Column,
JSON,
)
from opensipkd.iso8583.bjb.pbb.models import Log as BaseLog
class Log(BaseLog):
__table_args__ = dict(extend_existing=True)
bit_048_data = Column(JSON)
# Bersumber dari file yang dikirim oleh Bu Yardian Wensdi pada 25-9-2017
# bernama "Technical Specification ISO 8583.pdf". Pada halaman 2 tertulis
# Release 1.0, 2017, Arvid Theodorus.
from opensipkd.iso8583.network.structure import NETWORK_BITS
#################
# Redefine bits #
#################
TRANSACTION_BITS = NETWORK_BITS.copy()
TRANSACTION_BITS.update({
3: ['Processing', 'Processing Code', 'N', 6, 'n'],
4: ['Amount', 'Transaction Amount', 'N', 12, 'n'],
7: ['Transmission', 'Transmission Date and Time', 'N', 10, 'n'],
11: ['STAN', 'System Trace Audit Number', 'N', 6, 'n'],
32: ['Acquiring', 'Acquiring Institution Code', 'LL', 2+11, 'n'],
33: ['Forwarding', 'Forwarding Institution ID Code', 'LL', 2+97, 'n'],
37: ['Sequence', 'Retrieval Reference Number', 'N', 12, 'n'],
48: ['Additional', 'Additional Data', 'LLL', 3+200, 'ans'],
# 90: ['Original', 'Original Data Element', 'LLL', 3+31, 'ans'],
})
#########
# Bit 3 #
#########
INQUIRY_CODE = '360000'
PAYMENT_CODE = '560000'
#########################
# Response Code, Bit 39 #
#########################
RC_INSUFFICIENT_FUND = '03'
RC_OTHER = '04'
# RC_CREATE_PAYMENT = '05'
RC_NOT_AVAILABLE = '10'
RC_ALREADY_PAID = '13'
RC_PAYMENT_NOT_FOUND = '06'
RC_ALREADY_CANCELLED = '94'
###########################
# Invoice Profile, Bit 48 #
###########################
INVOICE_PROFILE = [
('Invoice ID', 22, 'N'),
('Nama', 30, 'A'),
('Nama Kecamatan', 30, 'A'),
('Nama Kelurahan', 45, 'A'),
('Tagihan', 12, 'N'),
('Denda', 12, 'N'),
('Total Bayar', 12, 'N'), # Pokok + Denda
('NTP', 16, 'N'), # Nomor Transaksi Pemda
]
import sys
from datetime import (
datetime,
date,
)
from configparser import ConfigParser
from argparse import ArgumentParser
help_tgl_bayar = 'digunakan --payment'
help_amount = 'digunakan --payment dan --reversal'
help_ntb = 'digunakan --payment dan --reversal'
help_stan = 'digunakan --payment dan --reversal'
help_host = 'nama host saat menjadi daemon'
def date_from_str(s):
d, m, y = s.split('-')
return date(int(y), int(m), int(d))
def get_option(argv):
pars = ArgumentParser()
pars.add_argument('conf')
pars.add_argument('--invoice-id', required=True)
pars.add_argument('--payment', action='store_true')
pars.add_argument('--tgl-bayar', help=help_tgl_bayar)
pars.add_argument('--reversal', action='store_true')
pars.add_argument('--amount', help=help_amount)
pars.add_argument('--ntb', help=help_ntb)
pars.add_argument('--stan', help=help_stan)
pars.add_argument('--host', help=help_host)
return pars.parse_args(argv)
def get_module_object(name):
module_obj = __import__(name)
sub_obj = None
for sub in name.split('.')[1:]:
if sub_obj:
sub_obj = getattr(sub_obj, sub)
else:
sub_obj = getattr(module_obj, sub)
return sub_obj
def show_dict(d, margin=2):
s_margin = ' ' * margin
keys = list(d.keys())
keys.sort()
for key in keys:
s_key = str(key).rjust(3)
val = d[key]
print('{}{}: {}'.format(s_margin, s_key, [val]))
def show_fix_length(f, margin=4):
s_margin = ' ' * margin
for key, x, y in f.struct:
val = f[key]
print('{}{}: {}'.format(s_margin, key, [val]))
def ack_message(iso):
if iso.ack_message:
print(iso.ack_message)
class App:
def __init__(self, argv=sys.argv):
self.option = get_option(argv[1:])
self.invoice_id = self.option.invoice_id
self.conf = ConfigParser()
self.conf.read(self.option.conf)
self.module_conf = dict(self.conf['main'])
if self.option.host:
self.module_conf['name'] = self.option.host
self.invoice_profile = {}
def set_conf(self, name, func):
if self.conf.has_option('main', name):
self.module_conf[name] = func(self.conf.get('main', name))
def doc_from_iso(self, iso):
return self.Doc(from_iso=iso, conf=self.module_conf)
def get_tgl_bayar(self):
if self.option.tgl_bayar:
return date_from_str(self.option.tgl_bayar)
return datetime.now()
def run(self):
module_name = self.conf.get('main', 'module')
module = get_module_object(module_name)
module.init(self.module_conf)
self.Doc = module.Doc
if self.option.reversal:
self.reversal()
else:
inq_response = self.inquiry()
if inq_response.getBit(39) == '00' and self.option.payment:
self.payment(inq_response)
def inquiry(self):
tgl_bayar = self.get_tgl_bayar()
inq_request = self.Doc()
inq_request.set_inquiry_request(tgl_bayar)
inq_request.set_invoice_id(self.invoice_id)
self.show('Bank kirim inquiry request', inq_request)
inq_response = self.doc_from_iso(inq_request)
inq_response.process()
ack_message(inq_response)
self.show('Pemda kirim inquiry response', inq_response)
return inq_response
def payment(self, inq_response):
tgl_bayar = self.get_tgl_bayar()
if self.option.ntb:
ntb = self.option.ntb
else:
ntb = datetime.now().strftime('%y%m%d%H%M%S')
if self.option.amount:
amount = self.option.amount
else:
amount = inq_response.get_amount()
pay_request = self.Doc()
pay_request.set_payment_request(tgl_bayar)
pay_request.set_invoice_id(self.invoice_id)
pay_request.set_amount(amount)
pay_request.set_ntb(ntb)
if self.option.stan:
pay_request.set_stan(self.option.stan)
self.show('Bank kirim payment request', pay_request)
pay_response = self.doc_from_iso(pay_request)
pay_response.process()
ack_message(pay_response)
self.show('Pemda kirim payment response', pay_response)
if pay_response.getBit(39) == '00':
print('NTP: {}'.format(pay_response.get_ntp()))
return pay_response
def reversal(self):
rev_request = self.Doc()
rev_request.set_reversal_request()
rev_request.set_invoice_id(self.invoice_id)
rev_request.set_ntb(self.option.ntb or '')
if self.option.stan:
rev_request.set_stan(self.option.stan)
if self.option.amount:
rev_request.set_amount(self.option.amount)
self.show('Bank kirim reversal request', rev_request)
rev_response = self.doc_from_iso(rev_request)
rev_response.process()
ack_message(rev_response)
self.show('Pemda kirim reversal response', rev_response)
return rev_response
def show(self, label, iso):
print(label)
print(' MTI {}'.format(iso.getMTI()))
show_dict(iso.get_values())
if iso.is_response():
for key, value in self.invoice_profile.items():
try:
profile = getattr(iso, value)
except AttributeError:
continue
print(' Bit {}'.format(key))
show_fix_length(profile, 4)
import sys
from opensipkd.iso8583.bjb.pbb.tools import str2tp
from .common import App as BaseApp
class App(BaseApp):
def __init__(self, *args, **kwargs):
BaseApp.__init__(self, *args, **kwargs)
self.invoice_profile = {48: 'invoice_profile'}
self.set_conf('persen_denda', float)
self.set_conf('kd_tp', str2tp)
def main(argv=sys.argv):
app = App(argv)
app.run()
import os
from setuptools import (
setup,
find_packages,
)
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.rst')) as f:
README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
CHANGES = f.read()
line = CHANGES.splitlines()[0]
version = line.split()[0]
requires = [
'opensipkd-iso8583-bjb @ '
'git+https://git.opensipkd.com/sugiana/opensipkd-iso8583-bjb.git',
]
setup(
name='opensipkd-iso8583-bni',
version=version,
description='Pengolahan ISO8583 untuk BNI',
long_description=README + '\n\n' + CHANGES,
author='Owo Sugiana',
author_email='sugiana@gmail.com',
license='PostgreSQL License',
packages=find_packages(),
install_requires=requires,
include_package_data=True,
zip_safe=False,
entry_points={
'console_scripts': [
'iso8583_bni_pbb_inquiry = '
'opensipkd.iso8583.bni.scripts.pbb_inquiry:main',
]
}
)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!