Commit 6db83713 by Solo Group

init

0 parents
*egg-info
*.pyc
__pycache__
*pytest_cache
test-*
test.ini
0.1 2019-02-04
--------------
- Kali pertama
include *.txt *.rst *.py
recursive-include opensipkd *.py
Metadata-Version: 1.0
Name: opensipkd-iso8583
Version: 0.1
Summary: Perangkat untuk Daemon ISO8583
Home-page: UNKNOWN
Author: Owo Sugiana
Author-email: sugiana@gmail.com
License: PostgreSQL License
Description: Perangkat untuk Daemon ISO8583
==============================
Di dalamnya ada:
* Class terkait pembuatan daemon TCP/IP, baik sebagai server maupun client.
* Class terkait dokumen ISO8583.
0.1 2019-02-04
--------------
- Kali pertama
Platform: UNKNOWN
Perangkat untuk Daemon ISO8583
==============================
Di dalamnya ada:
* Class terkait pembuatan daemon TCP/IP, baik sebagai server maupun client.
* Class terkait dokumen ISO8583.
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
\ No newline at end of file \ No newline at end of file
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
\ No newline at end of file \ No newline at end of file
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
\ No newline at end of file \ No newline at end of file
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
# from .doc import Doc
# from .job import Job
# todo: tunggu update di opensipkd.jsonrpc.auth karena belum support python 3
import sys
import hmac
import hashlib
import base64
from opensipkd.jsonrpc.auth import get_seconds
from random import choice
from string import (
ascii_uppercase,
ascii_lowercase,
digits,
)
def get_random_number(width=12):
return ''.join(choice(digits) for _ in range(width))
def get_jsonrpc(method, params):
return dict(jsonrpc='2.0', method=method, params=params, id=get_random_number(6))
# fungsi ini digunakan untuk membuat data yang akan dikirim ke server
def get_header(userid, password, time_stamp=None):
if not time_stamp:
time_stamp = str(get_seconds())
value = '&'.join([str(userid), str(time_stamp)])
password = str(password)
signature = hmac.new(key=str.encode(password), msg=str.encode(value),
digestmod=hashlib.sha256).digest()
if sys.version < '3':
encoded_signature = base64.encodestring(signature).replace('\n', '')
else:
encoded_signature = base64.encodebytes(signature).decode().replace('\n', '')
# signature = hmac.new(key=password, msg=value, digestmod=hashlib.sha256).digest()
return dict(userid=userid, signature=encoded_signature, key=time_stamp)
# import traceback
# # from opensipkd.iso8583.base.modules.network import models
# import re
# from opensipkd.iso8583.bjb.samsat.transaction import TransactionJsonRpc as Transaction
# from opensipkd.iso8583.bjb.samsat.structure import (
# INVOICE_ID,
# INVALID_NIK,
# INVOICE_PROFILE,
# INQUIRY_CODE,
# PAYMENT_CODE,
# RC_OK,
# RC_NOT_AVAILABLE,
# RC_ALREADY_PAID,
# RC_INVALID_NIK,
# RC_INVALID_NUMBER,
# RC_EXPIRE,
# RC_DUPLIKASI_TGL_AKHIR_PAJAK,
# ERR_INVALID_NUMBER,
# ERR_INVALID_NUMBER_2,
# ERR_NOT_AVAILABLE,
# ERR_ALREADY_PAID,
# ERR_INVALID_CHANNEL,
# ERR_INQUIRY_TIMEOUT,
# ERR_PAYMENT_TIMEOUT,
# ERR_PAYMENT_FAILED,
# ERR_OTHER,
# ERR_PAYMENT_NOT_FOUND,
# ERR_REVERSAL_DONE,
# ERR_REVERSAL_TIMEOUT,
# ERR_REVERSAL_FAILED,
# ERR_INVALID_CHANNEL,
# ERR_INVALID_NIK,
# ERR_DB,
# ERR_INVALID_BANK,
# ERR_EXPIRE,
# ERR_DUPLIKASI_TGL_AKHIR_PAJAK,
# )
#
# from opensipkd.tools import FixLength
# import sys
# if sys.version < 3:
# from StringIO import StringIO
# else:
# from io import StringIO
#
#
# def date2str(d):
# return d and d.strftime('%Y%m%d') or None
#
#
# class DbTransaction(Transaction):
# def __init__(self, *args, **kwargs):
# self.invoice_id = FixLength(INVOICE_ID)
# self.invalid_nik = FixLength(INVALID_NIK)
# self.invoice_profile = FixLength(self.get_invoice_profile_definition())
# # self.other_engine = OtherEngine(db_name, db_user, db_pass)
# Transaction.__init__(self, *args, **kwargs)
# self.rpc = self.conf and self.conf['samsat_banten'] or None
# if not self.conf or not self.rpc:
# raise ("Perbaiki konfigurasi")
#
#
# # @staticmethod
# def get_invoice_profile_definition(self):
# return INVOICE_PROFILE
#
# def is_allowed(self):
# return True
# # todo: to be updated
# # if 'allowed id' not in self.conf.host:
# # return True
# #
# # bank_id = int(self.from_iso.get_value(32))
# # return bank_id in self.conf['allowed id']
#
# ###########
# # Inquiry #
# ###########
# def inquiry_response_(self):
# if not self.is_allowed():
# return self.ack_not_allowed()
# self.setBit(4, 0)
# tagihan = self.get_invoice()
# if tagihan:
# self.setBit(4, tagihan['jumlah'] or 0)
# return tagihan
#
# def inquiry_response(self):
# self.inquiry_response_()
# try:
# pass
# except:
# self.ack_other('Ada kesalahan yang belum dipahami.')
# f = StringIO()
# traceback.print_exc(file=f)
# self.log_error(f.getvalue())
# f.close()
#
# def get_invoice_id_structure(self):
# invoice_id_raw = self.get_invoice_id_raw()
# invoice_id_raw = invoice_id_raw.strip().replace('.', '').strip()
# if len(invoice_id_raw) in [10,16]:
# if len(invoice_id_raw) == 10:
# invoice_id_raw = invoice_id_raw.ljust(16,' ')
# invoice_id_raw = invoice_id_raw.ljust(32,'0')
# self.log_info(invoice_id_raw)
# r = self.invoice_id.set_raw(invoice_id_raw)
# if not r:
# return self.ack_invalid_number_2(invoice_id_raw)
# self.invoice_id['Nomor Bayar'] = self.invoice_id['Nomor Bayar'].strip()
# if self.invoice_id['Nomor Identitas'] is None:
# self.invoice_id['Nomor Identitas'] = ''
# else:
# self.invoice_id['Nomor Identitas'] = \
# self.invoice_id['Nomor Identitas'].strip()
# self.invoice_id_raw = self.invoice_id['Nomor Bayar'].ljust(16) + \
# self.invoice_id['Nomor Identitas']
# return r
#
# def get_data(self):
# return dict(kd_bank=str(self.get_bank_id()).rjust(3, '0'),
# kd_channel=self.from_iso.get_channel(),
# invoice_no=self.invoice_id_raw[:16],
# kd_biller=self.rpc['kd_biller'],
# kd_produk=self.rpc['kd_produk']
# )
#
# def get_invoice(self):
# if not self.get_invoice_id_structure():
# return self.ack_invalid_number()
# if len(self.invoice_id['Nomor Bayar']) != 16:
# return self.ack_invalid_number()
# data = self.get_data()
# rows = self.send_rpc('inquiry', data)
#
# if 'error' in rows:
# code = rows['error']['code'] \
# and rows['error']['code'] or '91'
# code = len(str(code))>2 and '91' or code
# if code in ['01', '02', '03', '04', '06', '09',
# '10', '11', '12', '15' ,'99','24']:
# code = '55'
#
# elif code in ['05','23']:
# code='54'
# else:
# code='91'
#
# message = rows['error']['message'] and rows['error']['message'] or 'Link Down'
# self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
# nb=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas'],
# code=code,
# message=message))
#
# self.setBit(62, message)
# self.ack(code, message)
# return self.ack(code, message)
#
# if rows:
# invoice = rows['result']['data']
# self.set_profile(invoice)
# return invoice
# self.ack_inquiry_timeout()
#
# def get_bank_channel_id(self):
# bank_id = self.get_bank_id()
# bank_id = str(bank_id).zfill(3)
# channel_id = self.from_iso.get_channel_id()
# channel_id = self.from_iso.get_channel_name_to_id() + channel_id
# # channel_id = str(channel_id).zfill(7)
# return '{b}{c}'.format(b=bank_id, c=channel_id)
#
# def set_profile_(self, invoice):
# self.invoice_profile.from_dict({
# 'Nomor Bayar': invoice['invoice_no'],
# 'Nomor Rangka': invoice['no_rangka'],
# 'Nomor Mesin': invoice['no_mesin'],
# 'Nomor Identitas': invoice['no_identitas'],
# 'Nama Pemilik': invoice['nm_wp'],
# 'Alamat Pemilik': invoice['jln_wp'],
# 'Nomor Polisi': 'no_polisi' in invoice and invoice['no_polisi'] or '',
# 'Warna Plat': invoice['warna_tnkb'],
# 'Milik Ke': invoice['milik_ke'],
# 'Nama Jenis KB': invoice['jenis_op'],
# 'Nama Merk KB': 'nm_op' in invoice and invoice['nm_op'] or '',
# 'Nama Model KB': invoice['model_op'],
# 'Tahun Buatan': 'tahun_produksi' in invoice and invoice['tahun_produksi'] or invoice['tahun_produksi '],
# 'Tgl Akhir Pajak Lama': re.sub("\D", "", invoice['tgl_lama']),
# 'Tgl Akhir Pajak Baru': re.sub("\D", "", invoice['tgl_baru']),
# 'Pokok BBN': invoice['pokok_bbn'],
# 'Denda BBN': invoice['denda_bbn'],
# 'Pokok PKB': invoice['pokok_pkb'],
# 'Denda PKB': invoice['denda_pkb'],
# 'Pokok SWD': invoice['pokok_swd'],
# 'Denda SWD': invoice['denda_swd'],
# 'Pokok Adm STNK': invoice['pokok_adm_stnk'],
# 'Pokok Adm TNKB': invoice['pokok_adm_tnkb'],
# 'Jumlah': invoice['jumlah'],
# 'Keterangan': invoice['keterangan'],
# 'Kode Wilayah': invoice['reserved_01']})
# self.set_invoice_profile(self.invoice_profile.get_raw())
#
# def set_profile(self, invoice):
# self.set_profile_(invoice)
# # kode = invoice['kd_status']
# self.log_info('Nomor Bayar {nb} NIK {nik}'.format(
# nb=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas']))
# return self.ack()
#
# # if kode == '1':
# # return self.ack()
# # self.set_error_msg(invoice['ket'])
# # if kode == 'A':
# # nik_samsat = invoice['nik_nasabah'].strip()
# # if self.invoice_id['Nomor Identitas'] == nik_samsat:
# # return self.ack_not_available()
# # self.invalid_nik.from_dict({
# # 'Nomor Identitas Bank': self.invoice_id['Nomor Identitas'],
# # 'Nomor Identitas Pemprov': nik_samsat})
# # self.set_invoice_profile(self.invalid_nik.get_raw())
# # return self.ack_invalid_nik(invoice)
# # if kode == 'B':
# # return self.ack_other('Harus ke kantor SAMSAT')
# # if kode == 'F':
# # return self.ack_already_paid()
# # if kode == 'H':
# # return self.ack_expire()
# # if kode == 'C':
# # return self.ack_duplikasi_tgl_akhir_pajak()
# # if kode == 'G':
# # return self.ack_other('Jam pelayanan usai')
# # self.ack_other()
#
# def set_error_msg(self, msg):
# self.setBit(62, msg)
#
# def tgl_bayar(self):
# t = self.from_iso.get_transaction_date()
# return t.strftime('%m-%d-%Y')
#
# ###########
# # Payment #
# ###########
# def payment_response(self):
# self.payment_response_()
#
# def payment_response_(self):
# if not self.is_allowed():
# return self.ack_not_allowed()
# self.copy([4, self.get_bit_invoice_profile()])
# pay = self.get_payment()
# if not pay:
# return
# no_identitas=self.from_iso.get_invoice_id_raw()[16:]
# self.invoice_id_raw = ''.join([
# pay['invoice_no'].ljust(16),
# no_identitas])
# ntpd = pay['ntp'] # self.ntpd(bank_id)
# self.set_ntp(ntpd)
# return self.save_payment(ntpd)
#
# def get_payment(self):
# self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16].strip()
#
# if len(self.invoice_id_raw) == 16:
# data = self.get_data()
# data.update(
# dict(ntb=self.get_ntb(),
# tgl_transaksi=self.get_transaction_date().strftime('%Y%m%d'),
# jam_transaksi=self.get_transaction_time().strftime("%H%M%S"),
# amount=self.get_amount())
# )
# rows = self.send_rpc('payment', data)
# if 'error' in rows:
# if 'error' in rows['error']:
# rows = rows['error']
# code = rows['error']['code']
#
# message = rows['error']['message']
# self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
# nb=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas'],
# code=code,
# message=message))
# print('debug',message, code)
# if code in ['01', '02', '03', '04', '06', '09',
# '10', '11', '12', '15' ,'99','24','22']:
# code = '55'
# elif code in ['05','23']:
# code='54'
# else:
# code='91'
#
# self.setBit(62, message)
# self.ack(code[-2:], message)
# return
#
# if rows:
# invoice = 'result' in rows and rows['result']['data'] or None
# # self.set_profile(invoice)
# return invoice
# return
#
# elif self.get_invoice_id_structure():
# pass
# # q = DBSession.query(Payment).filter_by(
# # nomor_bayar=self.invoice_id['Nomor Bayar'],
# # nik=self.invoice_id['Nomor Identitas'])
# else:
# return
#
# return
#
# def save_payment(self, ntpd):
#
# # todo: save payment
# #
# channel_id = self.from_iso.get_channel_id()
# ntb = self.from_iso.get_ntb()
# total_bayar = self.from_iso.get_amount()
# pay = models.IsoPayment()
# pay.ntb = ntb
# pay.ntp = ntpd
# pay.invoice_no = self.invoice_id_raw[:16].strip()
# pay.nik = self.invoice_id_raw[16:32].strip()
# # pay.tgl_bayar = self.from_iso.get_transaction_date()
# pay.amount = total_bayar
# pay.channel_id = channel_id
# pay.channel_nm = self.from_iso.getBit(43)
# pay.bank_ip = self.get_bank_ip()
# pay.biller_id = self.rpc['kd_biller']
# # todo: mustbe transaction_date_time
# pay.tgl = self.from_iso.get_transaction_date()
#
# if 'id' in self.conf:
# pay.bank_id = self.conf.get('id')
# else:
# pay.bank_id = int(self.from_iso.get_value(32))
#
# # pay.iso_request = self.from_iso.raw.upper()
# # pay.transmission = self.from_iso.get_transmission_datetime()
# # pay.stan = self.from_iso.get_value(11)
# # pay.kd_wil = self.invoice_profile['Kode Wilayah']
# # pay.settlement = self.from_iso.get_settlement_date()
# # pay.bit_inv_profile = self.from_iso.get_invoice_id_raw()
# self.db_profile.commit(pay)
# self.ack()
#
# ############
# # Reversal #
# ############
# def execute_reversal(self):
# self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16].strip()
#
# if len(self.invoice_id_raw) == 16:
# data = self.get_data()
# data.update(
# dict(ntb=self.get_ntb(),
# tgl_transaksi=self.get_transaction_date().strftime('%Y%m%d'),
# jam_transaksi=self.get_transaction_time().strftime("%H%M%S"))
# )
# # penambahan parameters
# rows = self.send_rpc('reversal', data)
# if 'error' in rows:
# code = rows['error']['code']
# message = rows['error']['message']
# self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
# nb=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas'],
# code=code,
# message=message))
#
# self.setBit(62, message)
# self.ack(code, message)
# return
#
# if rows:
# row = 'result' in rows and rows['result']['data'] or None
# # self.set_profile(invoice)
# return row
# return
#
# elif self.get_invoice_id_structure():
# pass
# # q = DBSession.query(Payment).filter_by(
# # nomor_bayar=self.invoice_id['Nomor Bayar'],
# # nik=self.invoice_id['Nomor Identitas'])
# else:
# return
#
# return
#
# def reversal_response_(self):
# self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16]
# ntb = self.from_iso.get_ntb()
# q = self.db_profile.query(models.IsoPayment).filter_by(
# invoice_no=self.invoice_id_raw[:16].strip(),
# # nik=self.invoice_id_raw[16:].strip(),
# ntb=ntb)
#
# pay = q.first()
# if not pay:
# return self.ack_payment_not_found()
#
# # self.invoice_id_raw = ''.join([self.invoice_profile['Nomor Bayar'].strip(),
# # self.invoice_profile['Nomor Identitas'].strip()])
# q = self.db_profile.query(models.IsoReversal).filter_by(id=pay.id)
# rev = q.first()
# if rev:
# return self.ack_reversal_done()
#
# result = self.execute_reversal()
#
# if not result:
# return
#
# return self.save_reversal(pay, result['ntp'])
#
# def reversal_response(self):
# self.reversal_response_()
# try:
# pass
# except:
# self.ack_other('Ada kesalahan yang belum dipahami.')
# f = StringIO()
# traceback.print_exc(file=f)
# self.log_error(f.getvalue())
# f.close()
#
# def save_reversal(self, pay, ntpd):
# rev = models.IsoReversal()
# rev.id = pay.id
# #rev.iso_request = self.from_iso.raw.upper()
#
# # todo: seharusnya trnsaction_date_time
# rev.tgl = self.from_iso.get_transaction_date()
# rev.ntp = ntpd
# self.db_profile.commit(rev)
# self.ack()
#
# ###################
# # Acknowledgement #
# ###################
# def ack_not_allowed(self):
# msg = ERR_INVALID_BANK.format(bank_id=self.from_iso.get_value(32))
# self.ack(RC_INVALID_NUMBER, msg)
#
# def ack_invalid_number(self):
# msg = ERR_INVALID_NUMBER.format(nik=self.invoice_id['Nomor Identitas'])
# # self.ack(RC_INVALID_NUMBER, msg)
# self.ack(RC_NOT_AVAILABLE, msg)
# self.set_error_msg(msg)
#
# def ack_invalid_number_2(self, invoice_id_raw):
# msg = ERR_INVALID_NUMBER_2.format(invoice_id=invoice_id_raw)
# # self.ack(RC_INVALID_NUMBER, msg)
# self.ack(RC_NOT_AVAILABLE, msg)
# self.set_error_msg(msg)
#
# def ack_not_available(self):
# msg = ERR_NOT_AVAILABLE.format(invoice_id=self.invoice_id_raw)
# self.ack(RC_NOT_AVAILABLE, msg)
#
# def ack_expire(self):
# msg = ERR_EXPIRE.format(invoice_id=self.invoice_id_raw)
# self.ack(RC_EXPIRE, msg)
#
# def ack_duplikasi_tgl_akhir_pajak(self):
# msg = ERR_DUPLIKASI_TGL_AKHIR_PAJAK.format(invoice_id=self.invoice_id_raw)
# self.ack(RC_DUPLIKASI_TGL_AKHIR_PAJAK, msg)
#
# def ack_invalid_channel(self):
# nomor_bayar = self.invoice_id['Nomor Bayar']
# channel_id = self.from_iso.get_channel_id()
# msg = ERR_INVALID_CHANNEL.format(nomor_bayar=nomor_bayar,
# channel_id=channel_id)
# self.ack_other(msg)
#
# def ack_invalid_nik(self, invoice):
# msg = ERR_INVALID_NIK.format(
# identitas_bank=self.invoice_id['Nomor Identitas'],
# identitas_pemprov=invoice['nik_nasabah'].strip())
# self.ack(RC_NOT_AVAILABLE, msg)
#
# def ack_inquiry_timeout(self):
# msg = ERR_INQUIRY_TIMEOUT.format(
# kd_bayar=self.invoice_id['Nomor Bayar'])
# self.ack_other(msg)
#
# def ack_already_paid(self):
# msg = ERR_ALREADY_PAID.format(invoice_id=self.invoice_id_raw)
# self.ack(RC_ALREADY_PAID)
#
# def ack_db_error(self, db_error):
# self.log_error(db_error)
# self.ack_other(ERR_DB)
#
# def ack_payment_timeout(self):
# kd_bayar = self.invoice_profile['Nomor Bayar']
# ntb = self.from_iso.get_ntb()
# msg = ERR_PAYMENT_TIMEOUT.format(kd_bayar=kd_bayar, ntb=ntb)
# self.ack_other(msg)
#
# def ack_payment_failed(self, result):
# kd_bayar = self.invoice_profile['Nomor Bayar']
# ntb = self.from_iso.get_ntb()
# msg = ERR_PAYMENT_FAILED.format(kd_bayar=kd_bayar, ntb=ntb,
# kd_status=result['kd_status'])
# self.ack_other(msg)
#
# def ack_payment_not_found(self):
# ntb = self.from_iso.get_ntb()
# msg = ERR_PAYMENT_NOT_FOUND.format(invoice_id=self.invoice_id_raw,
# ntb=ntb)
# self.ack(RC_NOT_AVAILABLE, msg)
#
# def ack_reversal_done(self):
# ntb = self.from_iso.get_ntb()
# msg = ERR_REVERSAL_DONE.format(invoice_id=self.invoice_id_raw,
# ntb=ntb)
# self.ack(RC_ALREADY_PAID, msg)
#
# def ack_reversal_timeout(self):
# kd_bayar = self.invoice_profile['Nomor Bayar']
# ntb = self.from_iso.get_ntb()
# msg = ERR_REVERSAL_TIMEOUT.format(kd_bayar=kd_bayar, ntb=ntb)
# self.ack_other(msg)
#
# def ack_reversal_failed(self, result):
# kd_bayar = self.invoice_profile['Nomor Bayar']
# ntb = self.from_iso.get_ntb()
# msg = ERR_REVERSAL_FAILED.format(kd_bayar=kd_bayar, ntb=ntb,
# kd_status=result['kd_status'])
# self.ack_other(msg)
from .doc import Doc
from .job import Job
import traceback
# from opensipkd.iso8583.base.modules.network import models
import re
from opensipkd.iso8583.bjb.samsat.transaction import Transaction
from datetime import datetime
from opensipkd.iso8583.bjb.samsat.structure import (
INVOICE_ID,
INVALID_NIK,
INVOICE_PROFILE,
INQUIRY_CODE,
PAYMENT_CODE,
RC_OK,
RC_NOT_AVAILABLE,
RC_ALREADY_PAID,
RC_INVALID_NIK,
RC_INVALID_NUMBER,
RC_EXPIRE,
RC_DUPLIKASI_TGL_AKHIR_PAJAK,
ERR_INVALID_NUMBER,
ERR_INVALID_NUMBER_2,
ERR_NOT_AVAILABLE,
ERR_ALREADY_PAID,
ERR_INVALID_CHANNEL,
ERR_INQUIRY_TIMEOUT,
ERR_PAYMENT_TIMEOUT,
ERR_PAYMENT_FAILED,
ERR_OTHER,
ERR_PAYMENT_NOT_FOUND,
ERR_REVERSAL_DONE,
ERR_REVERSAL_TIMEOUT,
ERR_REVERSAL_FAILED,
ERR_INVALID_CHANNEL,
ERR_INVALID_NIK,
ERR_DB,
ERR_INVALID_BANK,
ERR_EXPIRE,
ERR_DUPLIKASI_TGL_AKHIR_PAJAK,
)
from opensipkd.string import FixLength
import sys
import json
import requests
from opensipkd.jsonrpc import get_random_number
# todo: harusnya diimport daro opensipkd.tools.rpc
from ..api import get_header, get_jsonrpc
if sys.version < '3':
from StringIO import StringIO
else:
from io import StringIO
CODE_54 = ['05', '23']
CODE_55 = ['01', '02', '03', '04', '06', '09', '10', '11', '12', '15', '99',
'24', '22']
def date2str(d):
return d and d.strftime('%Y%m%d') or None
class Doc(Transaction):
def __init__(self, *args, **kwargs):
self.conf = kwargs["conf"]
self.mod_conf = dict()
for key in self.conf['module_conf']:
if key.find('samsat_banten_') < 0:
continue
name = key[14:]
self.mod_conf[name] = self.conf['module_conf'][key]
del kwargs["conf"]
self.invoice_id = FixLength(INVOICE_ID)
self.invalid_nik = FixLength(INVALID_NIK)
self.invoice_profile = FixLength(self.get_invoice_profile_definition())
# self.other_engine = OtherEngine(db_name, db_user, db_pass)
Transaction.__init__(self, *args, **kwargs)
if not self.mod_conf:
raise ValueError("Perbaiki konfigurasi")
def get_channel(self):
return self.get_channel_id()
def send_rpc(self, method, message):
userid = self.mod_conf['user']
password = self.mod_conf['key']
url = self.mod_conf['url']
headers = get_header(userid, password)
params = dict(data=message)
data = get_jsonrpc(method, params)
self.log_info(url)
self.log_info("REQUEST {}".format(data))
results = requests.post(url, json=data, headers=headers) # data=jsondata,
if results.status_code != 200:
self.log_error(results)
self.log_error(results.text)
return
rows = results.text and json.loads(results.text) or None
self.log_info("RESPONSE {}".format(rows))
return rows
# @staticmethod
def get_invoice_profile_definition(self):
return INVOICE_PROFILE
def is_allowed(self):
return True
# todo: to be updated
# if 'allowed id' not in self.conf.host:
# return True
#
# bank_id = int(self.from_iso.get_value(32))
# return bank_id in self.conf['allowed id']
###########
# Inquiry #
###########
def inquiry_request(self, data):
for p in data:
self.setBit(int(p), data[p])
self.setMTI('0200')
self.set_stan()
def inquiry_response_(self):
if not self.is_allowed():
return self.ack_not_allowed()
self.setBit(4, 0)
tagihan = self.get_invoice()
if tagihan:
self.setBit(4, tagihan['jumlah'] or 0)
return tagihan
def inquiry_response(self):
self.inquiry_response_()
try:
pass
except:
self.ack_other('Ada kesalahan yang belum dipahami.')
f = StringIO()
traceback.print_exc(file=f)
self.log_error(f.getvalue())
f.close()
def get_invoice_id_structure(self):
invoice_id_raw = self.get_invoice_id_raw()
invoice_id_raw = invoice_id_raw.strip().replace('.', '').strip()
if len(invoice_id_raw) in [10, 16]:
if len(invoice_id_raw) == 10:
invoice_id_raw = invoice_id_raw.ljust(16, ' ')
invoice_id_raw = invoice_id_raw.ljust(32, '0')
self.log_info(invoice_id_raw)
r = self.invoice_id.set_raw(invoice_id_raw)
if not r:
return self.ack_invalid_number_2(invoice_id_raw)
self.invoice_id['Nomor Bayar'] = self.invoice_id['Nomor Bayar'].strip()
if self.invoice_id['Nomor Identitas'] is None:
self.invoice_id['Nomor Identitas'] = ''
else:
self.invoice_id['Nomor Identitas'] = \
self.invoice_id['Nomor Identitas'].strip()
self.invoice_id_raw = self.invoice_id['Nomor Bayar'].ljust(16) + \
self.invoice_id['Nomor Identitas']
return r
def get_data(self):
return dict(kd_bank=str(self.get_bank_id()).rjust(3, '0'),
kd_channel=self.from_iso.get_channel(),
invoice_no=self.invoice_id_raw[:16],
kd_biller=self.mod_conf['kd_biller'],
kd_produk=self.mod_conf['kd_produk']
)
def get_invoice(self):
if not self.get_invoice_id_structure():
return self.ack_invalid_number()
if len(self.invoice_id['Nomor Bayar']) != 16:
return self.ack_invalid_number()
data = self.get_data()
rows = self.send_rpc('inquiry', data)
if 'error' in rows:
code = rows['error']['code'] \
and rows['error']['code'] or '91'
code = len(str(code)) > 2 and '91' or code
if code in CODE_55:
code = '55'
elif code in CODE_54:
code = '54'
else:
code = '91'
message = rows['error']['message'] and rows['error']['message'] or 'Link Down'
self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
nb=self.invoice_id['Nomor Bayar'],
nik=self.invoice_id['Nomor Identitas'],
code=code,
message=message))
self.setBit(62, message)
self.ack(code, message)
return self.ack(code, message)
if rows:
invoice = rows['result']['data']
self.set_profile(invoice)
return invoice
self.ack_inquiry_timeout()
def get_bank_channel_id(self):
bank_id = self.get_bank_id()
bank_id = str(bank_id).zfill(3)
channel_id = self.from_iso.get_channel_id()
channel_id = self.from_iso.get_channel_name_to_id() + channel_id
# channel_id = str(channel_id).zfill(7)
return '{b}{c}'.format(b=bank_id, c=channel_id)
def set_profile_(self, invoice):
self.invoice_profile.from_dict({
'Nomor Bayar': invoice['invoice_no'],
'Nomor Rangka': invoice['no_rangka'],
'Nomor Mesin': invoice['no_mesin'],
'Nomor Identitas': invoice['no_identitas'],
'Nama Pemilik': invoice['nm_wp'],
'Alamat Pemilik': invoice['jln_wp'],
'Nomor Polisi': 'no_polisi' in invoice and invoice['no_polisi'] or '',
'Warna Plat': invoice['warna_tnkb'],
'Milik Ke': invoice['milik_ke'],
'Nama Jenis KB': invoice['jenis_op'],
'Nama Merk KB': 'nm_op' in invoice and invoice['nm_op'] or '',
'Nama Model KB': invoice['model_op'],
'Tahun Buatan': 'tahun_produksi' in invoice and invoice['tahun_produksi'] or invoice['tahun_produksi '],
'Tgl Akhir Pajak Lama': re.sub("\D", "", invoice['tgl_lama']),
'Tgl Akhir Pajak Baru': re.sub("\D", "", invoice['tgl_baru']),
'Pokok BBN': invoice['pokok_bbn'],
'Denda BBN': invoice['denda_bbn'],
'Pokok PKB': invoice['pokok_pkb'],
'Denda PKB': invoice['denda_pkb'],
'Pokok SWD': invoice['pokok_swd'],
'Denda SWD': invoice['denda_swd'],
'Pokok Adm STNK': invoice['pokok_adm_stnk'],
'Pokok Adm TNKB': invoice['pokok_adm_tnkb'],
'Jumlah': invoice['jumlah'],
'Keterangan': invoice['keterangan'],
'Kode Wilayah': invoice['reserved_01']})
self.set_invoice_profile(self.invoice_profile.get_raw())
def set_profile(self, invoice):
self.set_profile_(invoice)
# kode = invoice['kd_status']
self.log_info('Nomor Bayar {nb} NIK {nik}'.format(
nb=self.invoice_id['Nomor Bayar'],
nik=self.invoice_id['Nomor Identitas']))
return self.ack()
# if kode == '1':
# return self.ack()
# self.set_error_msg(invoice['ket'])
# if kode == 'A':
# nik_samsat = invoice['nik_nasabah'].strip()
# if self.invoice_id['Nomor Identitas'] == nik_samsat:
# return self.ack_not_available()
# self.invalid_nik.from_dict({
# 'Nomor Identitas Bank': self.invoice_id['Nomor Identitas'],
# 'Nomor Identitas Pemprov': nik_samsat})
# self.set_invoice_profile(self.invalid_nik.get_raw())
# return self.ack_invalid_nik(invoice)
# if kode == 'B':
# return self.ack_other('Harus ke kantor SAMSAT')
# if kode == 'F':
# return self.ack_already_paid()
# if kode == 'H':
# return self.ack_expire()
# if kode == 'C':
# return self.ack_duplikasi_tgl_akhir_pajak()
# if kode == 'G':
# return self.ack_other('Jam pelayanan usai')
# self.ack_other()
def set_error_msg(self, msg):
self.setBit(62, msg)
def tgl_bayar(self):
t = self.from_iso.get_transaction_date()
return t.strftime('%m-%d-%Y')
###########
# Payment #
###########
def payment_response(self):
self.payment_response_()
def payment_response_(self):
if not self.is_allowed():
return self.ack_not_allowed()
self.copy([4, self.get_bit_invoice_profile()])
pay = self.get_payment()
if not pay:
return
no_identitas = self.from_iso.get_invoice_id_raw()[16:]
self.invoice_id_raw = ''.join([
pay['invoice_no'].ljust(16),
no_identitas])
ntpd = pay['ntp'] # self.ntpd(bank_id)
self.set_ntp(ntpd)
return self.save_payment(ntpd)
def get_payment(self):
self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16].strip()
if len(self.invoice_id_raw) == 16:
data = self.get_data()
data.update(
dict(ntb=self.get_ntb(),
tgl_transaksi=self.get_transaction_date().strftime('%Y%m%d'),
jam_transaksi=self.get_transaction_time().strftime("%H%M%S"),
amount=self.get_amount())
)
rows = self.send_rpc('payment', data)
if 'error' in rows:
if 'error' in rows['error']:
rows = rows['error']
code = rows['error']['code']
message = rows['error']['message']
self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
nb=self.invoice_id['Nomor Bayar'],
nik=self.invoice_id['Nomor Identitas'],
code=code,
message=message))
if code in CODE_55:
code = '55'
elif code in CODE_54:
code = '54'
else:
code = '91'
self.setBit(62, message)
self.ack(code[-2:], message)
return
if rows:
invoice = 'result' in rows and rows['result']['data'] or None
# self.set_profile(invoice)
return invoice
return
elif self.get_invoice_id_structure():
pass
# q = DBSession.query(Payment).filter_by(
# nomor_bayar=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas'])
else:
return
return
def save_payment(self, ntpd):
# todo: save payment
#
channel_id = self.from_iso.get_channel_id()
ntb = self.from_iso.get_ntb()
total_bayar = self.from_iso.get_amount()
pay = models.IsoPayment()
pay.ntb = ntb
pay.ntp = ntpd
pay.invoice_no = self.invoice_id_raw[:16].strip()
pay.nik = self.invoice_id_raw[16:32].strip()
# pay.tgl_bayar = self.from_iso.get_transaction_date()
pay.amount = total_bayar
pay.channel_id = channel_id
pay.channel_nm = self.from_iso.getBit(43)
pay.bank_ip = self.get_bank_ip()
pay.biller_id = self.mod_conf['kd_biller']
# todo: mustbe transaction_date_time
pay.tgl = self.from_iso.get_transaction_date()
if 'id' in self.mod_conf:
pay.bank_id = self.mod_conf.get('id')
else:
pay.bank_id = int(self.from_iso.get_value(32))
# pay.iso_request = self.from_iso.raw.upper()
# pay.transmission = self.from_iso.get_transmission_datetime()
# pay.stan = self.from_iso.get_value(11)
# pay.kd_wil = self.invoice_profile['Kode Wilayah']
# pay.settlement = self.from_iso.get_settlement_date()
# pay.bit_inv_profile = self.from_iso.get_invoice_id_raw()
self.db_profile.commit(pay)
self.ack()
############
# Reversal #
############
def execute_reversal(self):
self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16].strip()
if len(self.invoice_id_raw) == 16:
data = self.get_data()
data.update(
dict(ntb=self.get_ntb(),
tgl_transaksi=self.get_transaction_date().strftime('%Y%m%d'),
jam_transaksi=self.get_transaction_time().strftime("%H%M%S"))
)
# penambahan parameters
rows = self.send_rpc('reversal', data)
if 'error' in rows:
code = rows['error']['code']
message = rows['error']['message']
self.log_info('Nomor Bayar {nb} NIK {nik} kode = {code}, {message}'.format(
nb=self.invoice_id['Nomor Bayar'],
nik=self.invoice_id['Nomor Identitas'],
code=code,
message=message))
self.setBit(62, message)
self.ack(code, message)
return
if rows:
row = 'result' in rows and rows['result']['data'] or None
# self.set_profile(invoice)
return row
return
elif self.get_invoice_id_structure():
pass
# q = DBSession.query(Payment).filter_by(
# nomor_bayar=self.invoice_id['Nomor Bayar'],
# nik=self.invoice_id['Nomor Identitas'])
else:
return
return
def reversal_response_(self):
self.invoice_id_raw = self.from_iso.get_invoice_id_raw()[:16]
ntb = self.from_iso.get_ntb()
q = self.db_profile.query(models.IsoPayment).filter_by(
invoice_no=self.invoice_id_raw[:16].strip(),
# nik=self.invoice_id_raw[16:].strip(),
ntb=ntb)
pay = q.first()
if not pay:
return self.ack_payment_not_found()
# self.invoice_id_raw = ''.join([self.invoice_profile['Nomor Bayar'].strip(),
# self.invoice_profile['Nomor Identitas'].strip()])
q = self.db_profile.query(models.IsoReversal).filter_by(id=pay.id)
rev = q.first()
if rev:
return self.ack_reversal_done()
result = self.execute_reversal()
if not result:
return
return self.save_reversal(pay, result['ntp'])
def reversal_response(self):
self.reversal_response_()
try:
pass
except:
self.ack_other('Ada kesalahan yang belum dipahami.')
f = StringIO()
traceback.print_exc(file=f)
self.log_error(f.getvalue())
f.close()
def save_reversal(self, pay, ntpd):
rev = models.IsoReversal()
rev.id = pay.id
# rev.iso_request = self.from_iso.raw.upper()
# todo: seharusnya trnsaction_date_time
rev.tgl = self.from_iso.get_transaction_date()
rev.ntp = ntpd
self.db_profile.commit(rev)
self.ack()
###################
# Acknowledgement #
###################
def ack_not_allowed(self):
msg = ERR_INVALID_BANK.format(bank_id=self.from_iso.get_value(32))
self.ack(RC_INVALID_NUMBER, msg)
def ack_invalid_number(self):
msg = ERR_INVALID_NUMBER.format(nik=self.invoice_id['Nomor Identitas'])
# self.ack(RC_INVALID_NUMBER, msg)
self.ack(RC_NOT_AVAILABLE, msg)
self.set_error_msg(msg)
def ack_invalid_number_2(self, invoice_id_raw):
msg = ERR_INVALID_NUMBER_2.format(invoice_id=invoice_id_raw)
# self.ack(RC_INVALID_NUMBER, msg)
self.ack(RC_NOT_AVAILABLE, msg)
self.set_error_msg(msg)
def ack_not_available(self):
msg = ERR_NOT_AVAILABLE.format(invoice_id=self.invoice_id_raw)
self.ack(RC_NOT_AVAILABLE, msg)
def ack_expire(self):
msg = ERR_EXPIRE.format(invoice_id=self.invoice_id_raw)
self.ack(RC_EXPIRE, msg)
def ack_duplikasi_tgl_akhir_pajak(self):
msg = ERR_DUPLIKASI_TGL_AKHIR_PAJAK.format(invoice_id=self.invoice_id_raw)
self.ack(RC_DUPLIKASI_TGL_AKHIR_PAJAK, msg)
def ack_invalid_channel(self):
nomor_bayar = self.invoice_id['Nomor Bayar']
channel_id = self.from_iso.get_channel_id()
msg = ERR_INVALID_CHANNEL.format(nomor_bayar=nomor_bayar,
channel_id=channel_id)
self.ack_other(msg)
def ack_invalid_nik(self, invoice):
msg = ERR_INVALID_NIK.format(
identitas_bank=self.invoice_id['Nomor Identitas'],
identitas_pemprov=invoice['nik_nasabah'].strip())
self.ack(RC_NOT_AVAILABLE, msg)
def ack_inquiry_timeout(self):
msg = ERR_INQUIRY_TIMEOUT.format(
kd_bayar=self.invoice_id['Nomor Bayar'])
self.ack_other(msg)
def ack_already_paid(self):
msg = ERR_ALREADY_PAID.format(invoice_id=self.invoice_id_raw)
self.ack(RC_ALREADY_PAID)
def ack_db_error(self, db_error):
self.log_error(db_error)
self.ack_other(ERR_DB)
def ack_payment_timeout(self):
kd_bayar = self.invoice_profile['Nomor Bayar']
ntb = self.from_iso.get_ntb()
msg = ERR_PAYMENT_TIMEOUT.format(kd_bayar=kd_bayar, ntb=ntb)
self.ack_other(msg)
def ack_payment_failed(self, result):
kd_bayar = self.invoice_profile['Nomor Bayar']
ntb = self.from_iso.get_ntb()
msg = ERR_PAYMENT_FAILED.format(kd_bayar=kd_bayar, ntb=ntb,
kd_status=result['kd_status'])
self.ack_other(msg)
def ack_payment_not_found(self):
ntb = self.from_iso.get_ntb()
msg = ERR_PAYMENT_NOT_FOUND.format(invoice_id=self.invoice_id_raw,
ntb=ntb)
self.ack(RC_NOT_AVAILABLE, msg)
def ack_reversal_done(self):
ntb = self.from_iso.get_ntb()
msg = ERR_REVERSAL_DONE.format(invoice_id=self.invoice_id_raw,
ntb=ntb)
self.ack(RC_ALREADY_PAID, msg)
def ack_reversal_timeout(self):
kd_bayar = self.invoice_profile['Nomor Bayar']
ntb = self.from_iso.get_ntb()
msg = ERR_REVERSAL_TIMEOUT.format(kd_bayar=kd_bayar, ntb=ntb)
self.ack_other(msg)
def ack_reversal_failed(self, result):
kd_bayar = self.invoice_profile['Nomor Bayar']
ntb = self.from_iso.get_ntb()
msg = ERR_REVERSAL_FAILED.format(kd_bayar=kd_bayar, ntb=ntb,
kd_status=result['kd_status'])
self.ack_other(msg)
from opensipkd.iso8583.network import Job as NetworkJob
from .doc import Doc
from datetime import time
class Job(NetworkJob):
# pass
def get_iso_class(self):
return Doc
def create_iso(self, from_iso=None):
cls = self.get_iso_class()
return cls(from_iso=from_iso, conf=self.conf)
def inquiry(self, p):
self.echo_time = time()
iso = self.create_iso()
iso.inquiry_request(p['data'])
return iso
import sys
import os
from optparse import OptionParser
import locale
import importlib
from datetime import datetime
import imp
from opensipkd.forwarder.base.iso8583_forwarder import conf
from opensipkd.forwarder.base.modules.ws_tools import send_rpc
def main(argv=sys.argv):
# global listen_ports
# global ip_conf
# global allowed_ips
# global hosts
# global logs
# global stop_dir
# global running
# global log
##############
# Blok Utama #
##############
global conf
conf_file = os.path.join('conf', 'forwarder.py')
host_name = 'bjb'
log_dir = 'logs'
method = 'get_tagihan'
host = 'bjb'
no_rangka = ""
no_ktp = ""
no_invoice = ""
amount = 0
pars = OptionParser()
pars.add_option('-p', '--no-pol')
pars.add_option('-r', '--no-rangka', default=no_rangka, help='diisi 5 digit no rangka')
pars.add_option('-k', '--no-ktp', default=no_ktp, help='diisi dengan no identitas')
pars.add_option('-a', '--amount', default=amount, help='diisi nilai pembayaran')
pars.add_option('-c', '--conf-file', default=conf_file, help='default ' + conf_file)
pars.add_option('-o', '--host', default=host, help='default ' + host)
pars.add_option('-i', '--invoice', default=no_invoice, help='no tagihan')
pars.add_option('-m', '--method', default=method, help='default ' + method)
option, remain = pars.parse_args(argv[1:])
conf_file = os.path.realpath(option.conf_file)
# print(conf_file)
conf = imp.load_source('conf', conf_file)
method = option.method
host = option.host
no_pol = option.no_pol
no_rangka = option.no_rangka
no_ktp = option.no_ktp
no_invoice = option.invoice
amount = option.amount
_host = conf.host
rpc = _host[host]['samsat_banten']
kini = datetime.now()
tgl_transaksi = kini.strftime("%Y%m%d")
jam_transaksi = kini.strftime("%H%M%S")
message = dict(kd_bank=conf.host[host]['id'],
kd_biller=rpc['kd_biller'],
kd_channel='6010',
kd_produk=rpc['kd_produk'],
)
if method == 'get_tagihan':
message.update(dict(no_polisi=no_pol))
elif method == 'get_kd_bayar':
message.update(
dict(no_polisi=no_pol,
no_identitas=no_ktp,
no_rangka=no_rangka
)
)
elif method == 'inquiry':
message.update(
dict(
invoice_no=no_invoice
)
)
elif method == 'payment':
message.update(
dict(
invoice_no=no_invoice,
ntb='12345BHJJJK',
amount=int(amount),
tgl_transaksi=tgl_transaksi,
jam_transaksi=jam_transaksi,
)
)
elif method == 'reversal':
message.update(
dict(
invoice_no=no_invoice,
ntb='12345BHJJJK',
amount=int(amount),
tgl_transaksi=tgl_transaksi,
jam_transaksi=jam_transaksi,
ntp='1993797040'
)
)
# rpc = conf.rpc
rows = send_rpc(rpc['user'], rpc['key'], rpc['url'], method, message)
# print(rpc['user'], rpc['key'], rpc['url'], method, message)
from datetime import datetime
from pprint import pprint
from time import sleep
from optparse import OptionParser
from opensipkd.forwarder.bjb.samsat.structure import INQUIRY_CODE
from .DbTransaction import DbTransaction
import os
import imp
def inquiry_request(iso, invoice_id, bank_id=None):
bank_id = bank_id and bank_id or '110'
kini = datetime.now()
iso.setBit(2, kini.strftime('%Y%m%d%H%M%S'))
iso.set_transaction_code(INQUIRY_CODE)
iso.setBit(12, kini.strftime('%H%M%S'))
iso.setBit(13, kini.strftime('%m%d'))
iso.setBit(15, kini.strftime('%m%d'))
iso.setBit(18, '6010')
iso.setBit(22, '021')
iso.setBit(32, bank_id)
iso.setBit(33, '00110')
# iso.setBit(35, '')
iso.setBit(37, kini.strftime('%H%M%S'))
iso.setBit(41, '000')
iso.setBit(42, '000000000000000')
iso.setBit(43, 'Nama Bank')
iso.setBit(49, '390')
# iso.setBit(59, 'PAY')
# iso.setBit(60, '142')
iso.setBit(61, invoice_id)
# iso.setBit(63, '')
# iso.setBit(102, '')
# iso.setBit(107, '')
# test_not_found = False
# name = '.'.join(['bppt', 'test'])
# try:
# module = __import__(name)
# except ImportError, test_not_found:
# name = '.'.join(['bppt', conf.module_name])
# module = __import__(name)
# area_module = getattr(module, conf.module_name)
# DbTransaction = area_module.DbTransaction
#
# if test_not_found:
# inquiry_request = default_inquiry_request
# else:
# inquiry_request = area_module.test.inquiry_request
class TestInquiry(object):
def __init__(self, argv):
self.option = get_option(argv)
if not self.option:
return
self.invoice_id = self.option.invoice_id.replace('-', '')
conf_file = self.option.conf_file
self.host = self.option.host
conf = imp.load_source('conf', conf_file)
self.conf = conf.host[self.host]
# dict(name=streamer_name, ip='127.0.0.1', bank_id=bank_id)
def run(self):
if not self.option:
return
print('\nBank kirim inquiry request')
req_iso = DbTransaction(conf=self.conf)
req_iso.set_transaction_request()
inquiry_request(req_iso, self.invoice_id)
raw = self.get_raw(req_iso)
print('\nPemda terima inquiry request')
from_iso = DbTransaction(conf=self.conf)
from_iso.setIsoContent(raw)
print('\nPemda kirim inquiry response')
resp_iso = DbTransaction(from_iso=from_iso, conf=self.conf)
func = getattr(resp_iso, from_iso.get_func_name())
func()
self.get_raw(resp_iso)
return resp_iso # Untuk test_payment.py
def get_raw(self, iso):
msg = 'MTI {mti}'.format(mti=iso.getMTI())
print(msg)
pprint(iso.getBitsAndValues())
raw = iso.getRawIso()
sleep(1)
print([raw])
return raw
def get_option(argv):
# bank = conf.host['streamer'] #'bjb'
pars = OptionParser()
conf_file = os.path.join('conf', 'forwarder.py')
host_name = 'bjb'
pars.add_option('-o', '--host', default=host_name, help='default ' + host_name)
pars.add_option('-i', '--invoice-id')
pars.add_option('-c', '--conf-file', default=conf_file, help='default ' + conf_file)
option, remain = pars.parse_args(argv)
if not option.invoice_id:
print('--invoice-id harus diisi.')
return
return option
def split_bank(s):
t = s.split(',')
if t[1:]:
streamer_name = t[0]
bank_id = int(t[1])
else:
streamer_name = s
bank_id = 0
return streamer_name, bank_id
def main(argv):
test = TestInquiry(argv)
test.run()
from datetime import datetime
from opensipkd.forwarder.bjb.samsat.structure import (
PAYMENT_CODE,
REQUEST_BITS,
)
from .test_inquiry import (
DbTransaction,
TestInquiry,
# test_not_found,
# area_module,
)
def payment_request(iso, inq_resp_iso, bank_id=None):
iso.copy(REQUEST_BITS, inq_resp_iso)
iso.set_transaction_code(PAYMENT_CODE)
ntb = datetime.now().strftime('%Y%m%d%H%M%S')[-12:]
print(">>NTB", ntb)
iso.set_ntb(ntb)
# if test_not_found:
# payment_request = default_payment_request
# else:
# payment_request = area_module.test.payment_request
class TestPayment(TestInquiry):
def run(self):
resp_iso = TestInquiry.run(self)
if not resp_iso.is_ok_response():
return resp_iso, None
print('\nBank kirim payment request')
req_iso = DbTransaction(conf=self.conf)
req_iso.set_transaction_request()
payment_request(req_iso, resp_iso) # , self.conf['bank_id']
raw = self.get_raw(req_iso)
print('\nPemda terima payment request')
from_iso = DbTransaction(conf=self.conf)
from_iso.setIsoContent(raw)
print('\nPemda kirim payment response')
resp_iso = DbTransaction(from_iso=from_iso, conf=self.conf) # , conf=self.conf
func = getattr(resp_iso, from_iso.get_func_name())
func()
self.get_raw(resp_iso)
return resp_iso, req_iso # Untuk test_reversal.py
def main(argv):
test = TestPayment(argv)
test.run()
from datetime import datetime
from test_payment import (
DbTransaction,
TestPayment,
)
def reversal_request(iso, pay_req_iso):
iso.copy(from_iso=pay_req_iso)
iso.set_reversal_request()
class TestReversal(TestPayment):
def run(self):
pay_resp_iso, pay_req_iso = TestPayment.run(self)
if not pay_resp_iso.is_ok_response():
return
print('Bank kirim reversal request')
req_iso = DbTransaction(conf=self.conf)
reversal_request(req_iso, pay_req_iso)
raw = self.get_raw(req_iso)
print('Pemda terima reversal request')
from_iso = DbTransaction(conf=self.conf)
from_iso.setIsoContent(raw)
print('Pemda kirim reversal response')
resp_iso = DbTransaction(from_iso=from_iso, conf=self.conf)
func = getattr(resp_iso, from_iso.get_func_name())
func()
self.get_raw(resp_iso)
def main(argv):
test = TestReversal(argv)
test.run()
from .doc import Doc
from .job import Job
import traceback
import re
from opensipkd.iso8583.bjb.samsat.transaction import Transaction
from opensipkd.string import FixLength
import sys
from opensipkd.jsonrpc.auth import get_header as json_rpc_header
import json
import requests
from opensipkd.jsonrpc import get_random_number
from opensipkd.string import (
DateTimeVar,
exception_message,
)
if sys.version < '3':
from StringIO import StringIO
else:
from io import StringIO
def date2str(d):
return d and d.strftime('%Y%m%d') or None
# fungsi ini digunakan untuk membuat data yang akan dikirim ke server
def get_jsonrpc(method, params):
return dict(jsonrpc='2.0', method=method, params=params, id=get_random_number(6))
# from datetime import datetime
# from ISO8583.ISOErrors import BitNotSet
# from opensipkd.string import (
# DateTimeVar,
# exception_message,
# )
# from opensipkd.waktu import create_datetime
# from ..doc import BaseISO8583
# from .structure import (
# NETWORK_BITS,
# RC_OK,
# RC_OTHER_ERROR,
# )
#
#
class Doc(Transaction):
def __init__(self, *args, **kwargs):
del kwargs['conf']
Transaction.__init__(self, *args, **kwargs)
self.transmission = DateTimeVar()
if self.from_iso:
self.set_response()
def inquiry_request(self, data):
for p in data:
print(p, data[p])
self.setBit(int(p), data[p])
self.setMTI('0200')
self.set_stan()
# def echo_response(self):
# self.set_network_response()
# self.ack()
# ####################
# # Network Sign Off #
# ####################
# def is_sign_off_request(self):
# return self.is_network_request() and \
# self.get_func_code() == '002' and \
# 'sign_off_response'
# def is_sign_off_response(self):
# return self.is_network_request() and self.get_func_code() == '002'
# def is_sign_off(self):
# return self.is_sign_off_request() or self.is_sign_off_response()
# def sign_off_request(self):
# self.set_func_code('002')
# def sign_off_response(self):
# self.set_network_response()
# self.ack()
# ###################
# # Acknowledgement #
# ###################
# def ack(self, code=RC_OK, msg=''):
# self.setBit(39, code)
# self.set_transmission()
# self.ack_log(msg)
# def ack_log(self, msg):
# pass
# def ack_other(self, msg='Ada masalah yang belum dipahami'):
# self.ack(RC_OTHER_ERROR, msg)
# def ack_function_not_found(self):
# self.ack_other('Fungsi tidak ditemukan')
# def ack_unknown(self):
# self.ack_other('Unknown')
from opensipkd.iso8583.network import Job as NetworkJob
from .doc import Doc
from datetime import time
class Job(NetworkJob):
def get_iso_class(self):
return Doc
def create_iso(self, from_iso=None):
cls = self.get_iso_class()
return cls(from_iso=from_iso, conf=self.conf)
def inquiry(self, p):
self.echo_time = time()
iso = self.create_iso()
iso.inquiry_request(p['data'])
return iso
from opensipkd.iso8583.network.structure import NETWORK_BITS
TRANSACTION_BITS = NETWORK_BITS.copy()
TRANSACTION_BITS.update({
2: ['PAN', 'Primary Account Number', 'LL', 99, 'n'],
3: ['Processing', 'Processing Code', 'N', 6, 'n'], # 301099 / 501099
4: ['Amount', 'Amount Transaction', 'N', 12, 'n'],
12: ['Time', 'Time Local Transaction', 'N', 6, 'n'],
13: ['Date', 'Date Local Transaction', 'N', 4, 'n'],
15: ['Settlement', 'Settlement Date', 'N', 4, 'n'],
18: ['Merchant', 'Merchant Type', 'N', 4, 'n'], # 6010 Teller, 6011 ATM
22: ['POS', 'POS Entry Mode Code', 'N', 3, 'n'], # '021'
32: ['Acquiring', 'Acquiring Institution Code', 'LL', 99, 'n'], # '110'
33: ['Forwarding', 'Forwarding Institution ID Code', 'LL', 99, 'n'], # '00110'
35: ['Track', 'Track 2 Data', 'LL', 99, 'n'],
37: ['Sequence', 'Sequence Number', 'N', 12, 'n'],
39: ['Response Code', 'Response Code', 'N', 2, 'n'],
41: ['Terminal', 'Terminal Identification Number', 'ANS', 8, 'ans'],
43: ['Card', 'Card Acceptor Name / Location', 'ANS', 40, 'ans'],
47: ['NTPD', 'Nomor Transaksi Pendapatan Daerah', 'LLL', 999, 'n'],
49: ['Currency', 'Transaction Currency Code', 'N', 3, 'n'],
61: ['Invoice ID', 'Invoice ID', 'LLL', 999, 'ans'],
62: ['Error', 'Error Message', 'LLL', 999, 'ans'],
})
#########################
# Response Code, Bit 39 #
#########################
RC_OK = '00'
RC_INVALID_NUMBER = '33'
RC_ALREADY_PAID = '54'
RC_NOT_AVAILABLE = '55'
RC_EXPIRE = '56'
RC_OTHER_ERROR = '76'
RC_INVALID_NIK = '85'
RC_DUPLIKASI_TGL_AKHIR_PAJAK = '87'
####################
# Response Message #
####################
ERR_INVALID_BANK = 'Bank ID {bank_id} tidak diperkenankan'
ERR_INVALID_NUMBER = 'NIK {nik} tidak benar, harus 16 angka'
ERR_INVALID_NUMBER_2 = 'Invoice ID {invoice_id} tidak benar'
ERR_INVALID_CHANNEL = 'Tidak diperkenankan nomor bayar {nomor_bayar} '\
'berawalan 01/02 melalui channel {channel_id}'
ERR_NOT_AVAILABLE = 'Invoice ID {invoice_id} tidak ada'
ERR_EXPIRE = 'Invoice ID {invoice_id} expire'
ERR_DUPLIKASI_TGL_AKHIR_PAJAK = 'Invoice ID {invoice_id} ganda. Perlu SMS '\
'untuk mendapatkan kode bayar.'
ERR_ALREADY_PAID = 'Invoice ID {invoice_id} sudah lunas'
ERR_ALREADY_PAID_2 = 'Invoice ID {invoice_id} status tidak tertagih tapi '\
'nilainya {nominal}'
ERR_INQUIRY_TIMEOUT = 'Jawaban inquiry tidak ada. kd_bayar {kd_bayar}'
ERR_OTHER = 'Under construction'
ERR_INVALID_NIK = 'NIK tidak sama. Identitas bank {identitas_bank}, '\
'identitas pemprov {identitas_pemprov}'
ERR_PAYMENT_TIMEOUT = 'Jawaban pembayaran tidak ada. '\
'kd_bayar {kd_bayar}, ntb {ntb}'
ERR_PAYMENT_FAILED = 'Jawaban pembayaran berstatus {kd_status}. '\
'kd_bayar {kd_bayar}, ntb {ntb}'
ERR_TRANSACTION_DATE = 'Transaction date {d} tidak benar'
ERR_SETTLEMENT_DATE = 'Settlement date {d} tidak benar'
# Saat reversal
ERR_PAYMENT_NOT_FOUND = 'Pembayaran tidak ditemukan. '\
'invoice_id {invoice_id}, ntb {ntb}'
ERR_REVERSAL_DONE = 'Pembayaran memang sudah dibatalkan. '\
'invoice_id {invoice_id}, ntb {ntb}'
ERR_REVERSAL_TIMEOUT = 'Jawaban pembatalan tidak ada. '\
'kd_bayar {kd_bayar}, ntb {ntb}'
ERR_REVERSAL_FAILED = 'Pembatalan gagal. kd_bayar {kd_bayar}, ntb {ntb}, '\
'kd_status {kd_status}'
ERR_DB = 'Database error'
##########################
# Bit 3 to name function #
##########################
INQUIRY_CODE = '301099'
PAYMENT_CODE = '541099'
REPRINT1_CODE = '901099'
REPRINT2_CODE = '601099'
########################
# Bit 61 saat MTI 0200 #
########################
INVOICE_ID = [
('Nomor Bayar', 16, 'A'),
('Nomor Identitas', 16, 'A'),
]
INVALID_NIK = [
('Nomor Identitas Bank', 16, 'N'),
('Nomor Identitas Pemprov', 16, 'N'),
]
########################
# Bit 61 saat MTI 0210 #
########################
INVOICE_PROFILE = [
('Nomor Bayar', 16),
('Nomor Rangka', 25),
('Nomor Mesin', 25),
('Nomor Identitas', 18),
('Nama Pemilik', 25),
('Alamat Pemilik', 40),
('Nomor Polisi', 9),
('Warna Plat', 6),
('Milik Ke', 3, 'N'),
('Nama Jenis KB', 15),
('Nama Merk KB', 15),
('Nama Model KB', 30),
('Tahun Buatan', 4, 'N'),
('Tgl Akhir Pajak Lama', 8, 'N'), # YMD
('Tgl Akhir Pajak Baru', 8, 'N'), # YMD
('Pokok BBN', 12, 'N'),
('Denda BBN', 12, 'N'),
('Pokok PKB', 12, 'N'),
('Denda PKB', 12, 'N'),
('Pokok SWD', 12, 'N'),
('Denda SWD', 12, 'N'),
('Pokok Adm STNK', 12, 'N'),
('Pokok Adm TNKB', 12, 'N'),
('Jumlah', 12, 'N'),
('Keterangan', 90),
('Kode Wilayah', 5),
]
from datetime import datetime
from ISO8583.ISOErrors import BitNotSet
from opensipkd.string import (
DateTimeVar,
DateVar,
exception_message,
)
from opensipkd.iso8583.network import Doc as BaseTransaction
from .structure import (
TRANSACTION_BITS,
INQUIRY_CODE,
PAYMENT_CODE,
REPRINT1_CODE,
REPRINT2_CODE,
RC_OK,
ERR_TRANSACTION_DATE,
ERR_SETTLEMENT_DATE,
ERR_OTHER,
)
from opensipkd.waktu import create_datetime
from iso8583_web.scripts.forwarder import Log
CHANNEL_NAMES = {
'INDOMARET': 1,
'ALFAMART': 2,
'ALFAMIDI': 3,
'TOKOPEDIA': 4,
'KASPRO': 5,
'BUKALAPAK': 6,
'VALUESTREAM': 9,
}
class Transaction(BaseTransaction, Log):
def __init__(self, *args, **kwargs):
BaseTransaction.__init__(self, *args, **kwargs)
self.transmission_datetime = DateTimeVar()
self.transaction_date = DateVar()
self.settlement_date = DateVar()
# Override
def get_bit_definition(self):
return TRANSACTION_BITS
# Override
def get_func_name(self):
return self.is_sign_on_request() or self.is_sign_off_request() or \
self.is_echo_request() or \
self.is_inquiry_request() or self.is_payment_request() or \
self.is_reversal()
# Override
def process(self):
func_name = self.from_iso.get_func_name()
if func_name:
func = getattr(self, func_name)
func()
else:
self.ack_function_not_found()
# Override
def set_response(self):
if self.from_iso.is_network_request():
BaseTransaction.set_response(self)
elif self.from_iso.is_transaction():
self.set_transaction_response()
elif self.from_iso.is_reversal():
self.set_reversal_response()
# Override
def setIsoContent(self, raw):
BaseTransaction.setIsoContent(self, raw)
self.raw = raw
def is_transaction_response(self):
return self.getMTI() == '0210'
def is_response(self):
return BaseTransaction.is_response(self) or self.is_transaction_response()
def is_transaction(self):
return self.getMTI() in ['0200', '0210']
def get_transaction_code(self):
return self.getBit(3)
def is_inquiry_response(self):
return self.getMTI() == '0210' and \
self.get_transaction_code() == INQUIRY_CODE
def is_inquiry_request(self):
if not self.is_transaction():
return
code = self.get_transaction_code()
return code == INQUIRY_CODE and 'inquiry_response'
def is_payment_request(self):
if not self.is_transaction():
return
code = self.get_transaction_code()
return code in (PAYMENT_CODE, REPRINT1_CODE, REPRINT2_CODE) and \
'payment_response'
def is_reprint(self):
return self.get_transaction_code() in (REPRINT1_CODE, REPRINT2_CODE)
def set_transaction_response(self):
kini = datetime.now()
self.setBit(12, kini.strftime('%H%M%S'))
self.setBit(13, kini.strftime('%m%d'))
self.setMTI('0210')
# Sesuai kolom yang berisi E (Equal) pada dokumentasi
self.copy([2, 3, 11, 12, 13, 15, 18, 22, 32, 33, 35, 37, 41, 43, 49,
61, 62])
def get_transmission_datetime(self):
raw = self.get_value(7)
self.transmission_datetime.set_raw(raw)
# without time zone
t = self.transmission_datetime.get_value()
# with time zone
t = create_datetime(t.year, t.month, t.day, t.hour, t.minute, t.second)
return t
def get_transaction_date(self):
raw = self.get_value(13)
self.transaction_date.set_raw(raw)
try:
return self.transaction_date.get_value()
except ValueError:
msg = ERR_TRANSACTION_DATE.format(d=raw)
self.ack_other(msg)
def get_settlement_date(self):
raw = self.get_value(15)
self.settlement_date.set_raw(raw)
try:
return self.settlement_date.get_value()
except ValueError:
msg = ERR_SETTLEMENT_DATE.format(d=raw)
self.ack_other(msg)
def get_bit_invoice_profile(self):
return 61
def get_invoice_id_raw(self):
return self.get_value(self.get_bit_invoice_profile())
def set_invoice_profile(self, raw):
self.setBit(self.get_bit_invoice_profile(), raw)
def get_ntb(self):
return self.get_value(37)
def set_ntb(self, ntb):
self.setBit(37, ntb)
def set_ntp(self, ntp):
self.setBit(47, ntp)
def get_amount(self):
return int(self.get_value(4))
def get_channel_id(self):
return self.get_value(18)
def get_channel_name(self):
try:
s = self.get_value(43)
except BitNotSet:
return ''
t = s.split()
return t and t[0] or ''
def get_channel_name_to_id(self):
name = self.get_channel_name()
if name in CHANNEL_NAMES:
s = CHANNEL_NAMES[name]
return str(s).zfill(3)
return '000'
def get_bank_ip(self):
return self.conf['ip']
def get_bank_id(self):
# if 'id' in self.conf:
# return self.conf['id'] # bjb
return int(self.from_iso.get_value(32))
def is_reversal(self):
s = self.getMTI()
return s[:2] == '04' and 'reversal_response'
def set_reversal_response(self):
s = self.from_iso.getMTI()
mti = s[:2] + '1' + s[3:] # 0400 -> 0410, 0401 -> 0411
self.setMTI(mti)
self.copy(from_iso=self.from_iso)
def ack_other(self, msg=ERR_OTHER):
self.setBit(62, msg)
BaseTransaction.ack_other(self, msg)
[egg_info]
tag_build =
tag_date = 0
import os
from setuptools import setup
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 = [
'ebcdic',
'ISO8583',
]
packages = [
'opensipkd.iso8583.bjb',
'opensipkd.iso8583.bjb.samsat',
'opensipkd.iso8583.bjb.samsat.banten',
]
setup(
name='opensipkd-iso8583-bjb-samsat-banten',
version=version,
description='Perangkat untuk Daemon ISO8583 BJB Samsat Banten',
long_description=README + '\n\n' + CHANGES,
author='Agus Gustiana',
author_email='aa.gustiana@gmail.com',
license='PostgreSQL License',
packages=packages,
install_requires=requires,
zip_safe=False,
)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!