Commit c932769d by Owo Sugiana

Kali pertama

0 parents
0.1 6-11-2020
-------------
- Kali pertama
Struktur Tabel LinkAja
======================
Ini berisi struktur tabel untuk mencatat transaksi yang di-request dari LinkAja
(produk PT Telkom).
[main]
db_url = postgresql://user:pass@localhost/db
File mode changed
from sqlalchemy import (
Column,
Integer,
Float,
DateTime,
String,
Text,
JSON,
ForeignKey,
func,
)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
# Tabel pertama saat ada request dari LinkAja
class Rpc(Base):
__tablename__ = 'linkaja_trx'
id = Column(Integer, primary_key=True) # Bill Ref
created = Column(
DateTime(timezone=True), nullable=False, server_default=func.now())
ip = Column(String(15), nullable=False)
conf_name = Column(String(16), nullable=False)
merchant = Column(String(100), nullable=False)
terminal = Column(String(100), nullable=False)
trx_type = Column(String(3), nullable=False)
msisdn = Column(String(20), nullable=False)
# Invoice ID = SPPT ID di PBB
acc_no = Column(String(64), nullable=False)
msg = Column(String(100))
trx_date = Column(DateTime(timezone=True), nullable=False)
# Dari inquiry response
amount = Column(Float)
# Dari inquiry response (Bill Ref),
# diisi saat payment request (bill_ref)
inquiry_id = Column(Integer, ForeignKey('linkaja_trx.id'))
# Dari payment request (trx_id)
ntb = Column(String(32))
# Penerjemahan bit 39
resp_code = Column(String(2))
# Penjelasan resp_code untuk pelanggan
resp_msg = Column(String(200))
# Penjelasan resp_code untuk audit sistem
resp_orig_msg = Column(String(200))
# Nama wajib pajak
biller_name = Column(String(200))
# Dari payment response (Transaction ID)
ntp = Column(String(32))
# Dari bit 11, dibutuhkan untuk reversal
stan = Column(String(6))
# Tabel kedua saat berkomunikasi dengan bank
class Bank(Base):
__tablename__ = 'linkaja_bank'
id = Column(Integer, primary_key=True)
created = Column(
DateTime(timezone=True), nullable=False, server_default=func.now())
rpc_id = Column(Integer, ForeignKey(Rpc.id), nullable=False)
url = Column(Text, nullable=False)
conf_name = Column(String(16), nullable=False)
request = Column(JSON, nullable=False)
response = Column(JSON)
import sys
from configparser import ConfigParser
from sqlalchemy import create_engine
from ..models import Base
def main(argv=sys.argv[1:]):
conf_file = argv[0]
conf = ConfigParser()
conf.read(conf_file)
db_url = conf.get('main', 'db_url')
engine = create_engine(db_url)
engine.echo = True
Base.metadata.create_all(engine)
import sys
from datetime import datetime
from argparse import ArgumentParser
from configparser import ConfigParser
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import transaction
from zope.sqlalchemy import register
from ..services import Query
IP = '127.0.0.1'
CONF_NAME = 'test'
default_merchant = 'ldmjakarta1'
default_terminal = 'Terminal Name'
default_msisdn = '628111234567'
help_amount = 'wajib saat --payment dan --reversal'
help_bill_ref = 'wajib saat payment dan reversal, '\
'diperoleh dari inquiry response'
help_trx_id = 'Nomor Transaksi Bank, '\
'opsional saat --payment, wajib saat --reversal'
help_merchant = 'default ' + default_merchant
def error(s):
print(s)
sys.exit()
def get_option(argv):
parser = ArgumentParser()
parser.add_argument('conf')
parser.add_argument('--invoice-id', required=True)
parser.add_argument('--payment', action='store_true')
parser.add_argument('--reversal', action='store_true')
parser.add_argument('--amount', type=int, help=help_amount)
parser.add_argument('--bill-ref', help=help_bill_ref)
parser.add_argument('--trx-id', help=help_trx_id)
parser.add_argument(
'--merchant', default=default_merchant, help=help_merchant)
parser.add_argument('--terminal', default=default_terminal)
parser.add_argument('--msisdn', default=default_msisdn)
parser.add_argument('--msg', default='')
parser.add_argument('--debug', action='store_true')
return parser.parse_args(argv)
class App:
def __init__(self, argv):
self.option = get_option(argv)
conf = ConfigParser()
conf.read(self.option.conf)
db_url = conf.get('main', 'db_url')
engine = create_engine(db_url)
engine.echo = self.option.debug
session_factory = sessionmaker(bind=engine)
self.db_session = session_factory()
register(self.db_session)
def get_method(self):
if self.option.payment:
return '022'
if self.option.reversal:
return '023'
return '021'
def get_transaction(self):
def required(name, default=None):
value = getattr(self.option, name)
if not value and not default:
error('--{} harus diisi'.format(name.replace('_', '-')))
p[name] = value or default
p = dict(
merchant=self.option.merchant,
terminal=self.option.terminal,
msisdn=self.option.msisdn,
acc_no=self.option.invoice_id,
trx_date=datetime.now().strftime('%Y%m%d%H%M%S'),
msg=self.option.msg)
p['trx_type'] = self.get_method()
if self.option.payment or self.option.reversal:
required('amount')
required('bill_ref')
if self.option.payment:
required('trx_id', datetime.now().strftime('%m%d%H%M%S'))
else:
required('trx_id')
return p
def run(self):
data = self.get_transaction()
if self.option.debug:
print(f'Input: {data}')
q = Query(data, self.db_session)
if self.option.payment:
inq = q.get_inquiry()
row = q.save(IP, CONF_NAME, inq=inq)
elif self.option.reversal:
pay = q.get_payment()
row = q.save(IP, CONF_NAME, pay=pay)
else:
row = q.save(IP, CONF_NAME)
print(f'Sudah disimpan dengan ID {row.id}')
def main(argv=sys.argv[1:]):
app = App(argv)
with transaction.manager:
app.run()
from opensipkd.string import FullDateTimeVar
from .models import Rpc
def date_from_str(s):
t = FullDateTimeVar()
t.set_raw(s)
return t.get_value()
class Query:
def __init__(self, data, db_session):
self.data = data
self.db_session = db_session
def save(self, ip, conf_name='linkaja', stan=None, inq=None, pay=None):
row = Rpc(
ip=ip,
conf_name=conf_name,
merchant=self.data['merchant'],
terminal=self.data['terminal'],
trx_type=self.data['trx_type'],
msisdn=self.data['msisdn'],
acc_no=self.data['acc_no'],
stan=stan)
row.trx_date = date_from_str(self.data['trx_date'])
if self.data.get('msg'):
row.msg = self.data['msg']
if self.data.get('amount'):
row.amount = int(self.data['amount'])
if self.data.get('trx_id'):
row.ntb = self.data['trx_id']
if inq:
row.inquiry_id = inq.id
elif pay:
row.inquiry_id = pay.inquiry_id
self.db_session.add(row)
self.db_session.flush()
self.db_session.expunge_all() # Agar field id terisi
return row
def get_inquiry(self):
bill_ref = int(self.data['bill_ref'])
q = self.db_session.query(Rpc).filter_by(id=bill_ref)
row = q.first()
if not row:
return
if row.acc_no == self.data['acc_no']:
return row
def get_payment(self):
bill_ref = int(self.data['bill_ref'])
q = self.db_session.query(Rpc).filter_by(
inquiry_id=bill_ref, trx_type='022')
q = q.order_by(Rpc.id.desc())
row = q.first()
if not row:
return
if row.acc_no == self.data['acc_no']:
return row
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 = [
'sqlalchemy',
'opensipkd-hitung @ '
'git+https://git.opensipkd.com/sugiana/opensipkd-hitung.git',
]
setup(
name='linkaja-models',
version=version,
description='Struktur tabel LinkAja',
long_description=README + '\n\n' + CHANGES,
author='Owo Sugiana',
author_email='sugiana@gmail.com',
license='PostgreSQL License',
packages=find_packages(),
install_requires=requires,
zip_safe=False,
entry_points={
'console_scripts': [
'linkaja_init_db = linkaja.scripts.init_db:main',
'linkaja_inquiry = linkaja.scripts.inquiry:main',
],
}
)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!