Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
Owo Sugiana
/
iso8583-web
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit a1c645b7
authored
Jul 19, 2020
by
Owo Sugiana
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Konfigurasi web yang lebih ringkas
1 parent
cbbddf07
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
213 additions
and
56 deletions
CHANGES.txt
README.rst
iso8583.ini → iso8583-bank.ini
iso8583-pemda.ini
iso8583_web/read_conf.py
iso8583_web/scripts/forwarder.py
iso8583_web/scripts/init_db_linkaja.py
iso8583_web/scripts/views/__init__.py
iso8583_web/scripts/views/jsonrpc.py
iso8583_web/scripts/views/linkaja/__init__.py
iso8583_web/scripts/views/linkaja/exceptions.py
iso8583_web/scripts/views/linkaja/structure.py
iso8583_web/scripts/web_client.py
iso8583_web/scripts/web_client_linkaja.py
CHANGES.txt
View file @
a1c645b
0.2.1 2020-07-19
----------------
- Konfigurasi web yang lebih ringkas
- LinkAja RC 48 saat payment tidak ditemukan
- Contoh konfigurasi untuk simulasi sebagai bank
- Dokumentasi yang lebih baik dan fokus pada transaksi
0.2 2020-06-30
--------------
- Jalur web juga bisa multi modul
...
...
README.rst
View file @
a1c645b
This diff is collapsed.
Click to expand it.
iso8583.ini
→
iso8583
-bank
.ini
View file @
a1c645b
...
...
@@ -7,14 +7,14 @@
keys
=
root, iso8583_web
[handlers]
keys
=
console
keys
=
console
, file
[formatters]
keys
=
generic
[logger_root]
level
=
INFO
handlers
=
console
handlers
=
console
, file
[logger_iso8583_web]
level
=
DEBUG
...
...
@@ -27,34 +27,29 @@ args = (sys.stderr,)
level
=
NOTSET
formatter
=
generic
[handler_file]
class
=
FileHandler
args
=
('/home/sugiana/log/bank.log', 'a')
level
=
DEBUG
formatter
=
generic
[formatter_generic]
format
=
%(asctime)s %(levelname)s %(message)s
# Aktifkan web server jika ingin simulasi sebagai bank dimana inquiry dkk
# bisa dilakukan melalui web client.
# [web]
# port = 7000
# threads = 12
#[web_host_linkaja]
#ip = 127.0.0.1
#module = iso8583_web.scripts.views.linkaja
#host = pemda
#[module_iso8583_web.scripts.views.linkaja]
#route_path = /linkaja
#db_url = postgresql://sugiana:a@localhost/agratek
[host_bjb]
[host_pemda]
ip
=
127.0.0.1
port
=
10002
listen
=
fals
e
listen
=
tru
e
streamer
=
bjb_with_suffix
[host_mitracomm]
ip
=
127.0.0.1
port
=
8583
streamer
=
mitracomm
active
=
false
timeout
=
60
module
=
opensipkd.iso8583.bjb.pbb.test
# Aktifkan web server dimana inquiry dkk bisa dilakukan melalui web client.
[web]
port
=
7000
threads
=
12
[web_rpc]
route_path
=
/rpc
host
=
pemda
module
=
iso8583_web.scripts.views.jsonrpc
iso8583-pemda.ini
0 → 100644
View file @
a1c645b
###
# logging configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys
=
root, iso8583_web
[handlers]
keys
=
console, file
[formatters]
keys
=
generic
[logger_root]
level
=
INFO
handlers
=
console, file
[logger_iso8583_web]
level
=
DEBUG
handlers
=
qualname
=
iso8583_web
[handler_console]
class
=
StreamHandler
args
=
(sys.stderr,)
level
=
NOTSET
formatter
=
generic
[handler_file]
class
=
FileHandler
args
=
('/home/sugiana/log/pemda.log', 'a')
level
=
DEBUG
formatter
=
generic
[formatter_generic]
format
=
%(asctime)s %(levelname)s %(message)s
[module_opensipkd.iso8583.bjb.pbb.bogor_kota]
db_url
=
postgresql://user:pass@localhost/db
db_pool_size
=
50
db_max_overflow
=
100
persen_denda
=
2
nip_pencatat
=
999999999
# Tempat pembayaran
kd_kanwil
=
01
kd_kantor
=
01
# Penerjemahan nilai bit NN menjadi kd_tp
# Prioritas sesuai urutan
kd_tp
=
bit42:TOKOPEDIA:46
bit42:BUKALAPAK:47
bit43:INDOMARET:48
bit43:ALFAMART:49
bit18:6010:69
bit18:6011:71
bit18:6012:72
bit18:6013:73
bit18:6014:74
bit18:6015:75
bit18:6016:76
bit18:6017:77
bit0:default:20
[host_bjb]
ip
=
127.0.0.1
port
=
10002
listen
=
false
streamer
=
bjb_with_suffix
timeout
=
60
module
=
opensipkd.iso8583.bjb.pbb.bogor_kota
[host_mitracomm]
ip
=
127.0.0.1
port
=
8583
listen
=
true
streamer
=
mitracomm
timeout
=
60
module
=
opensipkd.iso8583.bjb.pbb.bogor_kota
iso8583_web/read_conf.py
View file @
a1c645b
...
...
@@ -11,7 +11,7 @@ name_conf = dict()
allowed_ips
=
list
()
web
=
dict
()
web_
ip
_conf
=
dict
()
web_
path
_conf
=
dict
()
def
get_conf
(
ip
,
port
):
...
...
@@ -40,6 +40,13 @@ def get_int(conf, section, option, default):
return
default
def
get_list
(
conf
,
section
,
option
,
default
):
s
=
get_str
(
conf
,
section
,
option
,
''
)
if
s
:
return
s
.
split
()
return
default
MSG_DUPLICATE
=
'IP {ip} port {port} ganda. Perbaiki konfigurasi.'
...
...
@@ -74,8 +81,8 @@ def append_others(cfg, conf, section):
cfg
[
key
]
=
val
def
load_module
(
cfg
,
conf
,
section
,
default
):
cfg
[
'module'
]
=
get_str
(
conf
,
section
,
'module'
,
default
)
def
load_module
(
cfg
,
conf
,
section
):
cfg
[
'module'
]
=
conf
.
get
(
section
,
'module'
)
cfg
[
'module_obj'
]
=
get_module_object
(
cfg
[
'module'
])
module_section
=
'module_'
+
cfg
[
'module'
]
if
conf
.
has_section
(
module_section
):
...
...
@@ -92,14 +99,19 @@ def read_web_conf(conf, section):
web
[
'port'
]
=
conf
.
getint
(
section
,
'port'
)
web
[
'threads'
]
=
conf
.
getint
(
section
,
'threads'
)
return
if
section
.
find
(
'web_
host_
'
)
!=
0
:
if
section
.
find
(
'web_'
)
!=
0
:
return
cfg
=
dict
()
cfg
[
'name'
]
=
section
.
split
(
'_'
)[
-
1
]
cfg
[
'ip'
]
=
conf
.
get
(
section
,
'ip'
)
cfg
[
'host'
]
=
conf
.
get
(
section
,
'host'
)
load_module
(
cfg
,
conf
,
section
,
'iso8583_web.scripts.views.jsonrpc'
)
web_ip_conf
[
cfg
[
'ip'
]]
=
dict
(
cfg
)
cfg
[
'name'
]
=
section
.
split
(
'web_'
)[
-
1
]
cfg
[
'allowed_ip'
]
=
get_list
(
conf
,
section
,
'allowed_ip'
,
[])
append_others
(
cfg
,
conf
,
section
)
cfg
[
'module_obj'
]
=
get_module_object
(
cfg
[
'module'
])
try
:
f_init
=
getattr
(
cfg
[
'module_obj'
],
'init'
)
f_init
(
cfg
)
except
AttributeError
:
pass
web_path_conf
[
cfg
[
'route_path'
]]
=
dict
(
cfg
)
def
read_host_conf
(
conf
,
section
):
...
...
@@ -120,7 +132,7 @@ def read_host_conf(conf, section):
cfg
[
'echo'
]
=
get_boolean
(
conf
,
section
,
'echo'
,
not
cfg
[
'listen'
])
cfg
[
'timeout'
]
=
get_int
(
conf
,
section
,
'timeout'
,
60
)
append_others
(
cfg
,
conf
,
section
)
load_module
(
cfg
,
conf
,
section
,
'opensipkd.iso8583.network'
)
load_module
(
cfg
,
conf
,
section
)
if
cfg
[
'listen'
]:
if
cfg
[
'port'
]
not
in
listen_ports
:
listen_ports
.
append
(
cfg
[
'port'
])
...
...
iso8583_web/scripts/forwarder.py
View file @
a1c645b
...
...
@@ -20,7 +20,7 @@ from ..read_conf import (
read_conf
,
ip_conf
,
web
as
web_conf
,
web_
ip
_conf
,
web_
path
_conf
,
listen_ports
,
allowed_ips
,
get_conf
,
...
...
@@ -347,7 +347,7 @@ def start_web_server():
host
=
'0.0.0.0'
with
Configurator
()
as
config
:
config
.
include
(
'pyramid_tm'
)
for
ip
,
cfg
in
web_ip
_conf
.
items
():
for
path
,
cfg
in
web_path
_conf
.
items
():
cfg
[
'module_obj'
]
.
pyramid_init
(
config
)
config
.
scan
(
cfg
[
'module'
])
config
.
scan
(
__name__
)
...
...
iso8583_web/scripts/init_db_linkaja.py
View file @
a1c645b
...
...
@@ -10,5 +10,5 @@ def main(argv=sys.argv):
conf
.
read
(
conf_file
)
cf
=
conf
[
'module_iso8583_web.scripts.views.linkaja'
]
engine
=
create_engine
(
cf
[
'db_url'
])
engine
.
echo
t
=
True
engine
.
echo
=
True
Base
.
metadata
.
create_all
(
engine
)
iso8583_web/scripts/views/__init__.py
View file @
a1c645b
...
...
@@ -5,7 +5,7 @@ from time import (
from
opensipkd.tcp.connection
import
join_ip_port
from
iso8583_web.read_conf
import
(
name_conf
,
web_
ip
_conf
,
web_
path
_conf
,
)
from
iso8583_web.scripts.logger
import
(
log_web_info
,
...
...
@@ -122,13 +122,20 @@ class View(object):
return
found_conn
def
get_web_conf
(
self
):
return
web_
ip_conf
.
get
(
self
.
request
.
client_addr
)
return
web_
path_conf
.
get
(
self
.
request
.
path
)
def
get_iso_conf
(
self
):
web_conf
=
self
.
get_web_conf
()
name
=
web_conf
[
'host'
]
return
name_conf
[
name
]
def
validate
(
self
):
conf
=
self
.
get_web_conf
()
if
not
conf
[
'allowed_ip'
]:
return
if
self
.
request
.
client_addr
not
in
conf
[
'allowed_ip'
]:
raise
self
.
not_found_error
(
self
.
request
.
client_addr
)
def
not_found_error
(
self
,
hostname
):
msg
=
'Host {} tidak ditemukan di konfigurasi'
.
format
(
hostname
)
return
Exception
(
msg
)
...
...
iso8583_web/scripts/views/jsonrpc.py
View file @
a1c645b
...
...
@@ -12,6 +12,7 @@ from . import (
)
ROUTE
=
'rpc'
conf
=
dict
()
...
...
@@ -50,20 +51,24 @@ class View(BaseView):
def
log_send
(
self
,
p
):
BaseView
.
log_send
(
self
,
p
)
@jsonrpc_method
(
endpoint
=
'rpc'
)
@jsonrpc_method
(
endpoint
=
ROUTE
)
def
echo
(
self
,
p
):
self
.
validate
()
return
self
.
get_response
(
'echo'
,
'echo_request'
)
@jsonrpc_method
(
endpoint
=
'rpc'
)
@jsonrpc_method
(
endpoint
=
ROUTE
)
def
inquiry
(
self
,
p
):
self
.
validate
()
return
self
.
get_response
(
'inquiry'
,
p
)
@jsonrpc_method
(
endpoint
=
'rpc'
)
@jsonrpc_method
(
endpoint
=
ROUTE
)
def
payment
(
self
,
p
):
self
.
validate
()
return
self
.
get_response
(
'payment'
,
p
)
@jsonrpc_method
(
endpoint
=
'rpc'
)
@jsonrpc_method
(
endpoint
=
ROUTE
)
def
reversal
(
self
,
p
):
self
.
validate
()
return
self
.
get_response
(
'reversal'
,
p
)
...
...
@@ -75,4 +80,5 @@ def init(cfg):
# Dipanggil forwarder.py
def
pyramid_init
(
config
):
config
.
include
(
'pyramid_rpc.jsonrpc'
)
config
.
add_jsonrpc_endpoint
(
'rpc'
,
conf
[
'route_path'
])
config
.
add_jsonrpc_endpoint
(
ROUTE
,
conf
[
'route_path'
])
log_web_info
(
'JSON-RPC route path {}'
.
format
(
conf
[
'route_path'
]))
iso8583_web/scripts/views/linkaja/__init__.py
View file @
a1c645b
...
...
@@ -11,6 +11,7 @@ from pyramid.view import (
view_config
,
notfound_view_config
,
)
from
pyramid.response
import
Response
from
deform
import
(
Form
,
Button
,
...
...
@@ -23,6 +24,11 @@ from opensipkd.string import (
)
from
opensipkd.iso8583.bjb.pbb.structure
import
INVOICE_PROFILE
from
iso8583_web.scripts.tools
import
iso_to_dict
from
iso8583_web.read_conf
import
web_path_conf
from
iso8583_web.scripts.logger
import
(
log_web_info
,
log_web_error
,
)
from
..
import
(
WebJob
as
BaseWebJob
,
View
as
BaseView
,
...
...
@@ -38,6 +44,7 @@ from .exceptions import (
BaseError
,
AmountError
,
BillRefNotFound
,
PaymentNotFound
,
)
from
.structure
import
(
DataRequest
,
...
...
@@ -51,7 +58,7 @@ from .models import (
)
ROUTE
=
'
rpc
'
ROUTE
=
'
linkaja
'
RENDERER
=
'csv'
METHOD
=
{
'021'
:
'inquiry'
,
...
...
@@ -104,7 +111,7 @@ def get_payment(data):
DBSession
=
get_db_session
()
bill_ref
=
int
(
data
[
'bill_ref'
])
q
=
DBSession
.
query
(
Rpc
)
.
filter_by
(
inquiry_id
=
bill_ref
,
trx_type
=
data
[
'trx_type'
]
)
inquiry_id
=
bill_ref
,
trx_type
=
'022'
)
q
=
q
.
order_by
(
Rpc
.
id
.
desc
())
return
q
.
first
()
...
...
@@ -149,7 +156,6 @@ class csv_method(object):
kw
.
setdefault
(
'attr'
,
wrapped
.
__name__
)
kw
[
'_info'
]
=
info
.
codeinfo
# fbo action_method
print
(
'DEBUG wrapped {}'
.
format
(
wrapped
))
return
wrapped
...
...
@@ -237,7 +243,10 @@ class View(BaseView):
elif
iso_data
[
39
]
in
[
'33'
,
'55'
]:
err
=
InvoiceIdError
()
elif
iso_data
[
39
]
==
'54'
:
err
=
AlreadyPaidError
()
if
is_reversal
(
data
):
err
=
PaymentNotFound
()
else
:
err
=
AlreadyPaidError
()
elif
iso_data
[
39
]
==
'51'
:
err
=
AmountError
()
else
:
...
...
@@ -278,6 +287,7 @@ class View(BaseView):
@csv_method
(
route_name
=
ROUTE
)
def
view_trx
(
self
):
self
.
validate
()
if
not
self
.
request
.
POST
:
self
.
log_receive
(
'GET {}'
.
format
(
self
.
request
.
GET
))
raise
NeedPostError
()
...
...
@@ -294,6 +304,7 @@ class View(BaseView):
break
raise
InternalError
(
msg
)
data
=
dict
(
c
)
return
self
.
get_response
(
data
)
try
:
r
=
self
.
get_response
(
data
)
self
.
log_send
(
r
)
...
...
@@ -310,6 +321,27 @@ class View(BaseView):
self
.
log_receive
(
msg
,
True
)
return
self
.
request
.
exception
def
log_prefix
(
request
):
web_conf
=
web_path_conf
.
get
(
request
.
path
)
name
=
web_conf
[
'name'
]
return
'{} {} {}'
.
format
(
request
.
client_addr
,
name
,
id
(
request
))
@view_config
(
context
=
BaseError
)
def
view_exception
(
exc
,
request
):
r
=
InquiryResponse
()
r
[
'Response Code'
]
=
exc
.
code
r
[
'Notification Message'
]
=
exc
.
message
prefix
=
log_prefix
(
request
)
msg
=
'{} {} {}'
.
format
(
prefix
,
'Send'
,
r
)
log_web_error
(
msg
)
response
=
Response
(
str
(
r
))
response
.
status_int
=
200
return
response
# Dipanggil read_conf.py
def
init
(
cfg
):
conf
.
update
(
cfg
)
...
...
@@ -319,6 +351,7 @@ def init(cfg):
def
pyramid_init
(
config
):
config
.
add_renderer
(
RENDERER
,
'iso8583_web.scripts.views.linkaja.Renderer'
)
config
.
add_route
(
ROUTE
,
conf
[
'route_path'
])
log_web_info
(
'LinkAja route path {}'
.
format
(
conf
[
'route_path'
]))
pool_size
=
int
(
conf
.
get
(
'db_pool_size'
,
50
))
max_overflow
=
int
(
conf
.
get
(
'db_max_overflow'
,
100
))
engine
=
create_engine
(
...
...
iso8583_web/scripts/views/linkaja/exceptions.py
View file @
a1c645b
...
...
@@ -50,3 +50,8 @@ class AmountError(BaseError):
class
BillRefNotFound
(
BaseError
):
code
=
'47'
message
=
'bill_ref tidak ditemukan'
class
PaymentNotFound
(
BaseError
):
code
=
'48'
message
=
'Belum ada pembayaran'
iso8583_web/scripts/views/linkaja/structure.py
View file @
a1c645b
...
...
@@ -44,6 +44,9 @@ class InquiryResponse(Row):
Row
.
__setitem__
(
self
,
name
,
value
)
def
__str__
(
self
):
return
self
.
to_str
()
def
to_str
(
self
):
return
':'
.
join
(
list
(
self
))
def
from_err
(
self
,
err
):
...
...
iso8583_web/scripts/web_client.py
View file @
a1c645b
...
...
@@ -68,13 +68,23 @@ def send(p):
try
:
resp
=
requests
.
post
(
url
,
data
=
json
.
dumps
(
p
),
headers
=
headers
)
durations
[
key
]
=
time
()
-
start
json_resp
=
resp
.
json
()
log_info
(
'Response: {}'
.
format
(
json_resp
))
json_responses
[
key
]
=
json_resp
if
resp
.
status_code
==
200
:
json_resp
=
resp
.
json
()
log_info
(
'Response: {}'
.
format
(
json_resp
))
json_responses
[
key
]
=
json_resp
else
:
log_info
(
'Status Code: {}'
.
format
(
resp
.
status_code
))
log_info
(
'Body: {}'
.
format
([
resp
.
text
]))
json_responses
[
key
]
=
dict
(
fatal
=
resp
.
text
)
except
requests
.
exceptions
.
ConnectionError
as
e
:
durations
[
key
]
=
time
()
-
start
log_info
(
'Response: {}'
.
format
(
e
))
json_responses
[
key
]
=
dict
(
fatal
=
e
)
except
json
.
decoder
.
JSONDecodeError
as
e
:
durations
[
key
]
=
time
()
-
start
log_info
(
'Body: {}'
.
format
([
resp
.
text
]))
log_info
(
'Response: {}'
.
format
(
e
))
json_responses
[
key
]
=
dict
(
fatal
=
e
)
finally
:
end_threads
.
append
(
key
)
...
...
@@ -130,7 +140,7 @@ def show_durations():
key_slowest
=
key
total_duration
+=
duration
log_info
(
msg
)
if
key_fastest
:
if
key_fastest
!=
key_slowest
:
log_info
(
'Tercepat {}'
.
format
(
messages
[
key_fastest
]))
log_info
(
'Terlama {}'
.
format
(
messages
[
key_slowest
]))
log_info
(
'Rerata {} detik / request'
.
format
(
total_duration
/
len
(
durations
)))
...
...
iso8583_web/scripts/web_client_linkaja.py
View file @
a1c645b
...
...
@@ -146,7 +146,7 @@ def show_durations():
else
:
errors
[
err
]
=
1
log_info
(
'thread {} {} detik {}'
.
format
(
tid
,
duration
,
msg
))
if
tid_fastest
:
if
tid_fastest
!=
tid_slowest
:
log_info
(
'Tercepat {}'
.
format
(
messages
[
tid_fastest
]))
log_info
(
'Terlama {}'
.
format
(
messages
[
tid_slowest
]))
log_info
(
'Rerata {} detik / request'
.
format
(
total_duration
/
len
(
durations
)))
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment