Commit 6e056be1 by aagusti

Merge branch 'master' of https://git.opensipkd.com/taufik/esipkd

2 parents 34787f16 958acf40
......@@ -151,6 +151,8 @@ def main(global_config, **settings):
json_renderer.add_adapter(decimal.Decimal, lambda v, request: str(v))
config.add_renderer('json_rpc', json_renderer)
config.add_jsonrpc_endpoint('api-webr', '/api/webr', default_renderer="json_rpc")
config.add_jsonrpc_endpoint('bjbva-callback', '/bjbva/callback', default_renderer="json_rpc")
config.add_jsonrpc_endpoint('bjbqris-callback', '/bjbqris/callback', default_renderer="json_rpc")
routes = DBSession.query(Route.kode, Route.path, Route.nama, Route.factory).all()
for route in routes:
......
......@@ -41,7 +41,7 @@ from ..tools import as_timezone
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
TABLE_ARGS = {'extend_existing':True}
##############
# Base model #
......
from sqlalchemy import (
Column,
Integer,
Text,
DateTime,
ForeignKey,
UniqueConstraint,
String,
SmallInteger,
BigInteger,
Float,
Date,
)
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm import (
relationship,
backref
)
from ..models import (NamaModel, Base, DBSession, CommonModel, KodeModel, TABLE_ARGS, User)
import requests
import json
import sys
from .rpc import json_rpc_header, get_jsonrpc
from ..tools import date_from_str, ymd, ymdhms
import logging
log = logging.getLogger('BJBQRIS LOG')
from datetime import datetime, date, timedelta,time
def datetime_from_str(values):
separator = None
values = values.split()
value = values[0] # dd-mm-yyyy HH:MM:SS
tgl = date_from_str(value)
t = [0,0,0]
if len(values) > 1:
t = values[1].split(':')
return datetime(tgl.year, tgl.month, tgl.day, int(t[0]), int(t[1]), int(t[2]))
def cek_parameter(parameter):
if not parameter['bjbqris_url']:
log.error('bjbqris_url parameter belum ada')
return
if not parameter['bjbqris_user']:
log.error('bjbqris_user parameter belum ada')
return
if not parameter['bjbqris_key']:
log.error('bjbqris_key parameter belum ada')
return
return True
class BJBQRIS(KodeModel, Base):
__tablename__ = 'bjb_qris'
id = Column(Integer, primary_key=True)
client_type = Column(SmallInteger)
## 0: VA Offline
## 1: Ecommerce
## 2: Edupay
## 3: Pajak
## 4: Rumah Sakit
invoice_no = Column(String(16))
product_code = Column(String(2))
## 01 = BPHTB
## 02 = PBB
## 05 = SAMSAT
## 10 = PDL
## 30 = WEBR
## 90 = PERIZINAN
description = Column(String(128))
customer_name = Column(String(64))
customer_email = Column(String(128))
customer_phone = Column(String(32))
client_refnum = Column(String(128))
expired_date = Column(DateTime)
amount = Column(BigInteger)
billing_type = Column(String(1))
## o = open payment
## f = fixed payment
va_type = Column(String(1))
va_number = Column(String(32))
currency = Column(String(3))
customer_id = Column(String(32))
status = Column(String(1), server_default='0')
## 0 = belum dibayar
## 1 = dibayar sebagian
## 2 = dibayar penuh
## 3 = kadaluarsa
## 4 = disabled
cin = Column(String(4))
response_code = Column(String(4))
response_message = Column(String(128))
qrcode = Column(Text)
type = Column(String(64))
merchantName = Column(String(128))
transactionDate = Column(DateTime)
transactionStatus = Column(String(64))
transactionAmount = Column(BigInteger)
transactionReference = Column(String(128))
paymentReference = Column(String(64))
merchantBalance = Column(String(255))
merchantMsisdn = Column(String(128))
merchantEmail = Column(String(64))
merchantMpan = Column(String(64))
rrn = Column(String(64))
customerName = Column(String(128))
invoiceNumber = Column(String(128))
created = Column(DateTime, nullable=False, default=datetime.now,server_default='now()')
updated = Column(DateTime)
create_uid = Column(Integer, nullable=False, default=1,server_default='1')
update_uid = Column(Integer),
__table_args__ = TABLE_ARGS
@classmethod
def save(cls, values, row=None, **kwargs):
if not row:
row = cls()
row.from_dict(values)
if 'transaction_date' in values and not isinstance(values['transaction_date'], datetime):
values['transaction_date'] = datetime_from_str(values['transaction_date'])
DBSession.add(row)
DBSession.flush()
return row
@classmethod
def create_va(cls, values, parameter):
cek = cek_parameter(parameter)
if not cek:
return False
data = dict(
client_type = values['client_type'],
invoice_no = str(values['invoice_no']),
product_code = str(values['product_code']),
description = str(values['description']),
customer_name = str(values['customer_name']),
customer_email = str(values['customer_email']),
customer_phone = str(values['customer_phone']),
expired_date = str(values['expired_date']),
amount = str(values['amount'])
)
datava = send_rpc(parameter, 'create', data)
if not datava:
return False
saved = cls.save(datava)
return saved
def send_rpc(parameter, method, data):
headers = json_rpc_header(parameter['bjbqris_user'],parameter['bjbqris_key'])
params = get_jsonrpc(method, dict(data=data))
try:
resp = requests.post(url=parameter['bjbqris_url'],
data=json.dumps(params),
headers=headers)
try:
datava = json.loads(resp.content)
log.error("RESPONSE FROM VA")
log.error(resp.text)
if 'error' in datava:
log.error(resp.content)
return datava['result']['data']
except:
log.error('Response Error')
log.error(resp.content)
return False
return False
except requests.exceptions.RequestException as err:
log.error('Gagal membuat koneksi, silakan coba lagi beberapa saat')
return False
\ No newline at end of file
from sqlalchemy import (
Column,
Integer,
Text,
DateTime,
ForeignKey,
UniqueConstraint,
String,
SmallInteger,
BigInteger,
Float,
Date,
)
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm import (
relationship,
backref
)
from ..models import (NamaModel, Base, DBSession, CommonModel, KodeModel, TABLE_ARGS, User)
import requests
import json
import sys
from .rpc import json_rpc_header, get_jsonrpc
from ..tools import date_from_str, ymd, ymdhms
import logging
log = logging.getLogger('BJBVA LOG')
from datetime import datetime, date, timedelta,time
def datetime_from_str(values):
separator = None
values = values.split()
value = values[0] # dd-mm-yyyy HH:MM:SS
tgl = date_from_str(value)
t = [0,0,0]
if len(values) > 1:
t = values[1].split(':')
return datetime(tgl.year, tgl.month, tgl.day, int(t[0]), int(t[1]), int(t[2]))
def cek_parameter(parameter):
if not parameter['bjbva_url']:
log.error('bjbva_url parameter belum ada')
return
if not parameter['bjbva_user']:
log.error('bjbva_user parameter belum ada')
return
if not parameter['bjbva_key']:
log.error('bjbva_key parameter belum ada')
return
return True
class BJBVA(KodeModel, Base):
__tablename__ = 'bjb_va'
id = Column(Integer, primary_key=True)
client_type = Column(SmallInteger)
## 0: VA Offline
## 1: Ecommerce
## 2: Edupay
## 3: Pajak
## 4: Rumah Sakit
invoice_no = Column(String(16))
product_code = Column(String(2))
## 01 = BPHTB
## 02 = PBB
## 05 = SAMSAT
## 10 = PDL
## 30 = WEBR
## 90 = PERIZINAN
description = Column(String(128))
customer_name = Column(String(64))
customer_email = Column(String(128))
customer_phone = Column(String(32))
client_refnum = Column(String(128))
expired_date = Column(DateTime)
amount = Column(BigInteger)
billing_type = Column(String(1))
## o = open payment
## f = fixed payment
va_type = Column(String(1))
va_number = Column(String(32))
currency = Column(String(3))
customer_id = Column(String(32))
status = Column(String(1), server_default='0')
## 0 = belum dibayar
## 1 = dibayar sebagian
## 2 = dibayar penuh
## 3 = kadaluarsa
## 4 = disabled
cin = Column(String(4))
response_code = Column(String(4))
response_message = Column(String(128))
transaction_date = Column(DateTime)
transaction_amount = Column(BigInteger)
created = Column(DateTime, nullable=False, default=datetime.now,server_default='now()')
updated = Column(DateTime)
create_uid = Column(Integer, nullable=False, default=1,server_default='1')
update_uid = Column(Integer),
__table_args__ = TABLE_ARGS
@classmethod
def save(cls, values, row=None, **kwargs):
if not row:
row = cls()
row.from_dict(values)
if 'transaction_date' in values and not isinstance(values['transaction_date'], datetime):
values['transaction_date'] = datetime_from_str(values['transaction_date'])
DBSession.add(row)
DBSession.flush()
return row
@classmethod
def create_va(cls, values, parameter):
cek = cek_parameter(parameter)
if not cek:
return False
data = dict(
client_type = values['client_type'],
invoice_no = values['invoice_no'],
product_code = values['product_code'],
description = values['description'],
customer_name = values['customer_name'],
customer_email = values['customer_email'],
customer_phone = values['customer_phone'],
expired_date = values['expired_date'],
amount = str(values['amount'])
)
datava = send_rpc(parameter, 'create', data)
if not datava:
return False
saved = cls.save(datava)
return saved
@classmethod
def update_va(cls, values, row, parameter):
cek = cek_parameter(parameter)
if not cek:
return False
if 'expired_date' in values and isinstance(values['expired_date'], datetime):
values['expired_date'] = ymdhms(values['expired_date'])
data = dict(
va_number = values['va_number'],
invoice_no = values['invoice_no'],
product_code = values['product_code'],
amount = str(values['amount']),
expired_date = str(values['expired_date']),
customer_name = str(values['customer_name']),
customer_email = str(values['customer_email']),
customer_phone = str(values['customer_phone']),
description = str(values['description'])
)
datava = send_rpc(parameter, 'update', data)
if not datava:
return False
saved = cls.save(datava, row)
return saved
@classmethod
def inquiry_va(cls, row, parameter):
cek = cek_parameter(parameter)
if not cek:
return False
data = dict(
va_number = row.va_number,
invoice_no = row.invoice_no,
product_code = row.product_code
)
datava = send_rpc(parameter, 'inquiry', data)
if not datava:
return False
saved = cls.save(datava, row)
return saved
@classmethod
def cancel_va(cls, values, parameter):
cek = cek_parameter(parameter)
if not cek:
return False
row = cls.query().filter_by(va_number=values['va_number']).first()
data = dict(
va_number = row.va_number,
invoice_no = row.invoice_no,
product_code = row.product_code,
amount = str(row.amount),
expired_date = ymdhms(datetime.now()+timedelta(seconds=30)),
customer_name = row.customer_name,
customer_email = row.customer_email,
customer_phone = row.customer_phone,
description = row.description
)
datava = send_rpc(parameter, 'update', data)
if not datava:
return False
datava['status'] = '3'
saved = cls.save(datava, row)
return saved
def send_rpc(parameter, method, data):
headers = json_rpc_header(parameter['bjbva_user'],parameter['bjbva_key'])
params = get_jsonrpc(method, dict(data=data))
try:
resp = requests.post(url=parameter['bjbva_url'],
data=json.dumps(params),
headers=headers)
try:
datava = json.loads(resp.content)
log.error("RESPONSE FROM VA")
log.error(resp.text)
if 'error' in datava:
log.error(resp.content)
return datava['result']['data']
except:
log.error('Response Error')
log.error(resp.content)
return False
return False
except requests.exceptions.RequestException as err:
log.error('Gagal membuat koneksi, silakan coba lagi beberapa saat')
return False
\ No newline at end of file
......@@ -284,6 +284,18 @@ class Anggaran(NamaModel, Base):
rekenings = relationship("Rekening", backref=backref('anggarans'))
UniqueConstraint('rekening_id','tahun', name='anggaran_rekening_tahun')
class AnggaranOPD(NamaModel, Base):
__tablename__ = 'anggaran_unit'
status = Column(Integer, default=1)
tahun = Column(Integer, nullable=False, default=0)
rekening_id = Column(Integer, ForeignKey("rekenings.id"))
unit_id = Column(Integer, ForeignKey("units.id"))
murni = Column(BigInteger)
perubahan = Column(BigInteger)
rekenings = relationship("Rekening", backref=backref('anggaran_unit'))
units = relationship("Unit", backref=backref('anggaran_unit'))
UniqueConstraint('rekening_id','tahun', name='anggaran_unit_rekening_tahun')
class Wilayah(NamaModel,Base):
__tablename__ = 'wilayahs'
id = Column(Integer, primary_key=True)
......@@ -404,6 +416,10 @@ class ARInvoice(CommonModel, Base):
units = relationship("Unit", backref=backref('arinvoices'))
UniqueConstraint(tahun_id,unit_id,no_id,name='arinvoice_uq')
@classmethod
def query(cls):
return DBSession.query(cls)
class ARSspd(CommonModel, Base):
__tablename__ = 'arsspds'
id = Column(Integer, primary_key=True)
......
......@@ -22,9 +22,14 @@ from ..models import(
KodeModel,
NamaModel,
Base,
CommonModel
CommonModel,
User
)
from .isipkd import ARInvoice
import base64
import hashlib
import hmac
import sys
class DepartemenRoute(KodeModel, Base):
__tablename__ = 'departemen_route'
......@@ -34,3 +39,272 @@ class DepartemenRoute(KodeModel, Base):
ar_invoice_id = Column(Integer, ForeignKey(ARInvoice.id))
arinvoice = relationship(ARInvoice)
__table_args__ = {'extend_existing':True}
####################### API TOOL #######################################
from ..tools import (date_from_str, dict_to_str, to_str, get_settings)
from datetime import datetime
from pyramid_rpc.jsonrpc import JsonRpcError
now = datetime.now()
datenow = now.date()
lima_menit = 600
def auth_from_rpc(request):
settings = get_settings()
env = request.environ
if not ('HTTP_USERID' in env and 'HTTP_SIGNATURE' in env and
'HTTP_KEY' in env):
raise JsonRpcInvalidLoginError
http_userid = env['HTTP_USERID']
q = DBSession.query(User).filter_by(user_name=http_userid)
user = q.first()
if not user or user.status == 0:
raise JsonRpcInvalidLoginError
# bypass cek authentication for development
if http_userid=='admin' and 'devel' in settings and settings['devel']:
return user
time_stamp = int(env['HTTP_KEY'])
now = get_seconds()
if (not 'devel' in settings or not settings['devel']) and abs(now - time_stamp) > lima_menit:
raise JsonRpcInvalidTimeError
header = json_rpc_header(http_userid, user.api_key, time_stamp)
if header['signature'] != env['HTTP_SIGNATURE']:
raise JsonRpcInvalidLoginError
return user
def json_rpc_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', '')
return dict(userid=userid, signature=encoded_signature, key=time_stamp)
def get_jsonrpc(method, params):
return dict(jsonrpc='2.0', method=method, params=params, id=get_random_number(6))
class JsonRpcNotImplementedError(JsonRpcError):
code = -40000
message = "Method Not Implemented"
class JsonRpcDbUrlNotFoundError(JsonRpcError):
code = -40001
message = "DB URL Connection Not Found"
class JsonRpcDbConnectionError(JsonRpcError):
code = -40002
message = "DB Connection Not Found"
class JsonRpcDataNotFoundError(JsonRpcError):
code = -40003
message = "Error Data Not Found"
class JsonRpcDataFoundError(JsonRpcError):
code = -40004
message = "Error Data Found"
# error terkait authentication dan authorization
class JsonRpcInvalidLoginError(JsonRpcError):
code = -41001
message = "Invalid RPC User/Password"
class JsonRpcInvalidNikError(JsonRpcError):
code = -41002
message = 'NIK Tidak Valid'
class JsonRpcNikFoundError(JsonRpcError):
code = -41003
message = 'NIK Sudah Ada'
class JsonRpcMobileFoundError(JsonRpcError):
code = -41004
message = 'No HP Sudah Digunakan'
class JsonRpcInvalidMobileError(JsonRpcError):
code = -41004
message = 'No HP Tidak Valid'
class JsonRpcInvalidDataError(JsonRpcError):
code = -41005
message = 'Data Tidak Valid'
class JsonRpcEmailFoundError(JsonRpcError):
code = -41006
message = 'e-mail Sudah Digunakan'
class JsonRpcInvalidEmailError(JsonRpcError):
code = -41007
message = 'e-mail Tidak Valid'
class JsonRpcMailError(JsonRpcError):
code = -41008
message = 'Gagal autentikasi mail server'
class JsonRpcUserFoundError(JsonRpcError):
code = -41009
message = 'User sudah digunakan'
class JsonRpcRegisterFailError(JsonRpcError):
code = -41010
message = 'Gagal Registrasi User'
class JsonRpcProfileFailError(JsonRpcError):
code = -41011
message = 'Gagal Update Profile'
class JsonRpcGetPasswordError(JsonRpcError):
code = -41012
message = 'Gagal Request Password'
class JsonRpcUserNotFoundError(JsonRpcError):
code = -41013
message = 'User Tidak Ada'
class JsonRpcInvalidTimeError(JsonRpcError):
code = -41014
message = 'Periksa Date Time Server'
class JsonRpcPermissionError(JsonRpcError):
code = -41015
message = 'Hak Akses dibatasi'
# error terkait transaksi
class JsonRpcInvalidInvoiceError(JsonRpcError):
code = -50001
message = 'Invalid No Bayar'
class JsonRpcBankNotFoundError(JsonRpcError):
code = -51001
message = 'Bank Not Found'
class JsonRpcBillNotFoundError(JsonRpcError):
code = -52001
message = 'Bill Not Found'
class JsonRpcBillAllreadyPaidError(JsonRpcError):
code = -52002
message = 'Bill Allready Paid'
class JsonRpcBillDifferentError(JsonRpcError):
code = -52003
message = 'Bill Amount Different'
class JsonRpcNtbNotFoundError(JsonRpcError):
code = -53001
message = 'NTB Not Found'
class JsonRpcNtbNotValidError(JsonRpcError):
code = -53002
message = 'NTB Not Valid'
# Reversal Message
class JsonRpcPaymentNotFoundError(JsonRpcError):
code = -54001
message = 'Payment Not Found'
class JsonRpcPaymentNotOwnerError(JsonRpcError):
code = -54002
message = 'Not Your Payment'
class JsonRpcPaymentOpenError(JsonRpcError):
code = -54003
message = 'Payment Open'
class JsonRpcReversedError(JsonRpcError):
code = -54004
message = 'Payment Reversed'
class JsonRpcReversalError(JsonRpcError):
code = -54005
message = 'Cannot Reversed'
# Biller Status
class JsonRpcBillerNotFoundError(JsonRpcError):
code = -55001
message = 'Biller Not Found'
class JsonRpcBillerNetworkError(JsonRpcError):
code = -55002
message = 'Biller Network unrecognized'
class JsonRpcProdukNotFoundError(JsonRpcError):
code = -56001
message = 'Produk Not Found'
def custom_error(code, message):
cls = JsonRpcError()
cls.code = code
cls.message = message
cls.message = message
raise cls
def get_mandatory(data, values):
for value in values:
if not value in data or data[value] == '' or data[value] == None:
raise JsonRpcInvalidDataError(message="{} Not Found".format(value))
def get_seconds():
begin_unix_time = datetime(1970, 1, 1)
durasi = datetime.utcnow() - begin_unix_time
return int(durasi.total_seconds())
def get_random_number(width=12):
return ''.join(choice(digits) \
for _ in range(width))
def clear_null_value(values):
# digunakan untuk menghapus dictionary yang value nya null
tobe_del = []
for value in values:
if not values[value]:
tobe_del.append(value)
for value in tobe_del:
del values[value]
return values
def ymd(tgl):
return tgl.strftime('%Y-%m-%d')
\ No newline at end of file
......@@ -80,7 +80,7 @@ def set_sequence(orm):
seq_name = table_seq(orm.__table__)
if not seq_name:
return
row = DBSession.query(orm).order_by('id DESC').first()
row = DBSession.query(orm).order_by(text('id DESC')).first()
last_id = row and row.id or 1
sql = "SELECT setval('%s', %d)" % (seq_name, last_id)
engine = DBSession.bind
......
......@@ -243,3 +243,20 @@ id,kode,nama,path,factory,perm_name,disabled,created,updated,create_uid
258,"ranking-det","Ranking Detail","/ranking/det",,"read",0,"2020-10-13 08:38:45",,1
259,"rek-det","Rekening Detail","/rek/det",,"read",0,"2020-10-13 08:38:45",,1
260,"chart-det","Chart Detail","/chart/det",,"read",0,"2020-10-13 08:38:45",,1
261,"anggaran-opd","Anggaran OPD","/anggaran/opd",,"read",0,"2015-03-08 16:45:45",,1
262,"anggaran-opd-act","Baca Anggaran OPD","/anggaran/opd/{act}/act",,"read",0,"2015-03-08 16:45:45",,1
263,"anggaran-opd-add","Tambah Anggaran OPD","/anggaran/opd/add",,"add",0,"2015-03-08 16:45:45",,1
264,"anggaran-opd-edit","Edit Anggaran OPD","/anggaran/opd/{id}/edit",,"edit",0,"2015-03-08 16:45:45",,1
265,"anggaran-opd-delete","Hapus Anggaran OPD","/anggaran/opd/{id}/delete",,"delete",0,"2015-03-08 16:45:45",,1
266,"anggaran-opd-csv","CSV Anggaran OPD","/anggaran/opd/{csv}/csv",,"read",0,"2015-03-08 16:45:45",,1
267,"anggaran-opd-pdf","PDF Anggaran OPD","/anggaran/opd/{pdf}/pdf",,"read",0,"2015-03-08 16:45:45",,1
268,"bjbva","BJB VA","/bjbva",,"read",0,"2022-06-24 16:45:45",,1
269,"bjbva-add","BJB VA Add","/bjbva/add",,"read",0,"2022-06-24 16:45:45",,1
270,"bjbva-edt","BJB VA Edit","/bjbva/{id}/edt",,"read",0,"2022-06-24 16:45:45",,1
271,"bjbva-del","BJB VA Hapus","/bjbva/{id}/del",,"read",0,"2022-06-24 16:45:45",,1
272,"bjbva-act","","/bjbva/{act}/act",,"read",0,"2022-06-24 16:45:45",,1
273,"bjbqris","BJB QRIS","/bjbqris",,"read",0,"2022-06-24 16:45:45",,1
274,"bjbqris-add","BJB QRIS Add","/bjbqris/add",,"read",0,"2022-06-24 16:45:45",,1
275,"bjbqris-act","","/bjbqris/{act}/act",,"read",0,"2022-06-24 16:45:45",,1
\ No newline at end of file
......@@ -5,6 +5,7 @@ from sqlalchemy import (
engine_from_config,
select,
)
from sqlalchemy.sql import text
from sqlalchemy.schema import CreateSchema
from pyramid.paster import (
get_appsettings,
......@@ -18,6 +19,10 @@ from ..models import (
)
from ..models.isipkd import *
from ..models.rpc import *
from ..models.bjb_va import *
from ..models.bjb_qris import *
from sqlalchemy.dialects import oracle
import initial_data
from tools import mkdir
......@@ -72,9 +77,14 @@ def usage(argv):
sys.exit(1)
def create_schema(engine, schema):
sql = select([('schema_name')]).\
select_from('information_schema.schemata').\
where("schema_name = '%s'" % schema)
sql = select([text('schema_name')]). \
select_from(text('information_schema.schemata')). \
where(text("schema_name = '%s'" % schema))
if isinstance(engine.dialect, oracle.dialect):
sql = select([text('owner')]). \
select_from(text('dba_segments')). \
where(text("owner = '%s'" % schema.upper()))
print(sql)
q = engine.execute(sql)
if not q.fetchone():
engine.execute(CreateSchema(schema))
......
......@@ -171,8 +171,35 @@ def date_from_str(value):
def dmy(tgl):
return tgl.strftime('%d-%m-%Y')
def dmyhms(t):
return t.strftime('%d-%m-%Y %H:%M:%S')
def ymd(tgl):
return tgl.strftime('%Y-%m-%d')
def ymdhms(date):
if isinstance(date, str):
return date
return date.strftime('%Y-%m-%d %H:%M:%S')
def dmyhms(date):
if isinstance(date, str):
return date
return date.strftime('%d-%m-%Y %H:%M:%S')
def datetime_from_str(values):
separator = None
values = values.split()
value = values[0] # dd-mm-yyyy HH:MM:SS
tgl = date_from_str(value)
t = [0,0,0]
if len(values) > 1:
t = values[1].split(':')
return datetime(tgl.year, tgl.month, tgl.day, int(t[0]), int(t[1]), int(t[2]))
def dmy_to_date(tgl):
return datetime.strptime(tgl, '%d-%m-%Y')
def dMy(tgl):
return str(tgl.day) + ' ' + NAMA_BULAN[tgl.month][1] + ' ' + str(tgl.year)
def next_month(year, month):
if month == 12:
......@@ -710,3 +737,11 @@ def round_up(value):
if isinstance(value, int):
value = float(value)
return int(round(value+0.4999))
def get_tmp():
settings = get_settings()
if 'tmp_files' in settings and settings['tmp_files']:
tmpf = settings['tmp_files'].strip('/')
return str(tmpf)+'/'
else:
return str("/tmp/")
\ No newline at end of file
......@@ -9,16 +9,67 @@ from pyramid.security import (remember, forget, authenticated_userid,)
from deform import (Form, ValidationFailure, widget,)
from ..tools import dmy, date_from_str, int_to_roman, round_up
from sqlalchemy import func, and_, case
from sqlalchemy.sql import text
from collections import namedtuple
from sqlalchemy.orm.properties import RelationshipProperty
from sqlalchemy.sql.expression import asc, desc
# ColumnTuple = namedtuple('ColumnDT', ['column_name', 'mData', 'search_like', 'filter'])
from ..models import (DBSession, User,)
from ..models.isipkd import(
ARSspd, ARInvoice, Unit, Rekening, Anggaran
ARSspd, ARInvoice, Unit, Rekening, Anggaran, AnggaranOPD
)
from pyramid.view import notfound_view_config
import logging
log = logging.getLogger(__name__)
from datatables import DataTables as BaseDataTables, ColumnDT
class DataTables(BaseDataTables):
def sorting(self):
"""Construct the query, by adding sorting(ORDER BY) on the columns needed to be applied on
"""
sorting = []
Order = namedtuple('order', ['name', 'dir'])
if self.request_values.get('iSortCol_0') \
and self.request_values.get('iSortingCols') > 0:
for i in range(int(self.request_values['iSortingCols'])):
sorting.append(Order( self.columns[int(self.request_values['iSortCol_'+str(i)])].column_name,
self.request_values['sSortDir_'+str(i)]))
for sort in sorting:
tmp_sort_name = sort.name.split('.')
obj = getattr(self.sqla_object, tmp_sort_name[0])
if not hasattr(obj, "property"): #hybrid_property or property
sort_name = sort.name
if hasattr(self.sqla_object, "__tablename__"):
tablename = self.sqla_object.__tablename__
else:
tablename = self.sqla_object.__table__.name
elif isinstance(obj.property, RelationshipProperty): # Ex: ForeignKey
# Ex: address.description => description => addresses.description
sort_name = "".join(tmp_sort_name[1:])
if not sort_name:
# Find first primary key
sort_name = obj.property.table.primary_key.columns \
.values()[0].name
tablename = obj.property.table.name
else: #-> ColumnProperty
sort_name = sort.name
if hasattr(self.sqla_object, "__tablename__"):
tablename = self.sqla_object.__tablename__
else:
tablename = self.sqla_object.__table__.name
sort_name = "%s.%s" % (tablename, sort_name)
self.query = self.query.order_by(
asc(text(sort_name)) if sort.dir == 'asc' else desc(text(sort_name)))
###############################################################################
# Not Found
......@@ -192,17 +243,18 @@ def view_home(request):
# .all()
invoices = DBSession.query(
case([
(Anggaran.perubahan > 0,
func.coalesce(Anggaran.perubahan,0))
(AnggaranOPD.perubahan > 0,
func.coalesce(AnggaranOPD.perubahan,0))
],
else_= func.coalesce(Anggaran.murni,0)).label('jumlah'),
else_= func.coalesce(AnggaranOPD.murni,0)).label('jumlah'),
func.trim(Rekening.kode).label('rek_kode'),
Anggaran.kode.label('kode'),
Anggaran.nama.label('nama'),
).join(Rekening, Rekening.id == Anggaran.rekening_id).\
filter(Anggaran.tahun==dates['year']).order_by(Anggaran.kode)\
AnggaranOPD.kode.label('kode'),
AnggaranOPD.nama.label('nama'),
).join(Rekening, Rekening.id == AnggaranOPD.rekening_id).\
filter(AnggaranOPD.tahun==dates['year']).order_by(AnggaranOPD.kode)\
.all()
for i in invoices:
# print(">>>>i", i)
## JIKA ADA FILTER DEPARTEMEN DI HEADER
if 'unit' in request.params and request.params['unit']:
if i.kode.strip().startswith(request.params['unit'].strip()):
......@@ -244,6 +296,7 @@ def view_home(request):
data_dashboard['sopd'] = sorted(data_dashboard['sopd'], key = lambda i: (i['realisasi']), reverse=True)
i=-1
for opd in data_dashboard['sopd']:
# print(">>>>opd", opd)
i+=1
if i < 10:
data_dashboard['sopd10'].append(dict(
......
import sys
import re
from email.utils import parseaddr
from sqlalchemy import not_, func, or_, desc
from datetime import datetime
from pyramid.view import (
view_config,
)
from pyramid.httpexceptions import (
HTTPFound,
)
import colander
from deform import (
Form,
widget,
ValidationFailure,
)
from ..models import DBSession
from ..models.isipkd import(
Pajak,
Rekening,
Unit,
UnitRekening,
UserUnit,
Anggaran,
AnggaranOPD
)
from daftar import STATUS, deferred_status, daftar_rekening, deferred_rekening, daftar_rekening1, deferred_rekening1, auto_rekening_nm, deferred_unit, daftar_unit, auto_unit_nm, auto_user_nm
from ..security import group_in
from datatables import (
ColumnDT, DataTables)
from esipkd.tools import DefaultTimeZone, _DTstrftime, _DTnumberformat, _DTactive
SESS_ADD_FAILED = 'Gagal tambah anggaran'
SESS_EDIT_FAILED = 'Gagal edit anggaran'
########
# List #
########
@view_config(route_name='anggaran-opd', renderer='templates/anggaran-opd/list.pt',
permission='read')
def view_list(request):
return dict(rows={})
#######
# Add #
#######
def form_validator(form, value):
def err_kode():
raise colander.Invalid(form,
'Kode rekening anggaran %s sudah digunakan oleh ID %d' % (
value['kode'], found.id))
if 'id' in form.request.matchdict:
uid = form.request.matchdict['id']
q = DBSession.query(AnggaranOPD).filter_by(id=uid)
r = q.first()
else:
r = None
q = DBSession.query(AnggaranOPD).filter_by(kode=value['kode'])
found = q.first()
if r:
if found and found.id != r.id:
err_kode()
class AddSchema(colander.Schema):
moneywidget = widget.MoneyInputWidget(
size=20, options={'allowZero':True,
'precision':0
})
kode = colander.SchemaNode(
colander.String(),
missing = colander.drop,
widget=widget.HiddenWidget(),
oid="kode")
nama = colander.SchemaNode(
colander.String(),
missing = colander.drop,
widget=widget.HiddenWidget(),
oid="nama")
unit_id = colander.SchemaNode(
colander.Integer(),
widget = deferred_unit,
oid="unit_id",
title="OPD")
rekening_id = colander.SchemaNode(
colander.Integer(),
widget=widget.HiddenWidget(),
oid="rekening_id")
rekening_kd = colander.SchemaNode(
colander.String(),
oid="rekening_kd",
title="Kode Rekening")
rekening_nm = colander.SchemaNode(
colander.String(),
oid="rekening_nm",
title="Uraian Rekening")
murni = colander.SchemaNode(
colander.Integer(),
default = 0,
widget = moneywidget,
oid = "murni")
perubahan = colander.SchemaNode(
colander.Integer(),
default = 0,
widget = moneywidget,
oid = "perubahan")
tahun = colander.SchemaNode(
colander.Integer(),
missing = colander.drop)
status = colander.SchemaNode(
colander.Integer(),
widget=deferred_status,
title="Status")
class EditSchema(AddSchema):
id = colander.SchemaNode(colander.Integer(),
missing=colander.drop,
widget=widget.HiddenWidget(readonly=True))
def get_form(request, class_form):
schema = class_form(validator=form_validator)
schema = schema.bind(daftar_status = STATUS,
daftar_unit = daftar_unit())
schema.request = request
return Form(schema, buttons=('simpan','batal'))
def save(values, row=None):
if not row:
row = AnggaranOPD()
row.from_dict(values)
print "----- LEWAT -------------------"
row.murni = re.sub("[^0-9]", "", row.murni)
row.perubahan = re.sub("[^0-9]", "", row.perubahan)
if not row.kode:
k = DBSession.query(Rekening.kode).filter(Rekening.id==row.rekening_id).first()
row.kode = k
if not row.nama:
x = DBSession.query(Rekening.nama).filter(Rekening.id==row.rekening_id).first()
row.nama = x
if not row.tahun:
row.tahun = datetime.now().strftime('%Y')
DBSession.add(row)
DBSession.flush()
return row
def save_request(values, request, row=None):
if 'id' in request.matchdict:
values['id'] = request.matchdict['id']
row = save(values, row)
request.session.flash('AnggaranOPD %s %s sudah disimpan.' % (row.kode, row.nama))
def route_list(request):
return HTTPFound(location=request.route_url('anggaran-opd'))
def session_failed(request, session_name):
r = dict(form=request.session[session_name])
del request.session[session_name]
return r
@view_config(route_name='anggaran-opd-add', renderer='templates/anggaran-opd/add.pt',
permission='add')
def view_add(request):
form = get_form(request, AddSchema)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
c = form.validate(controls)
except ValidationFailure, e:
return dict(form=form)
#return HTTPFound(location=request.route_url('anggaran-add'))
save_request(dict(controls), request)
return route_list(request)
elif SESS_ADD_FAILED in request.session:
return session_failed(request, form) #, SESS_ADD_FAILED)
return dict(form=form)
########
# Edit #
########
def query_id(request):
return DBSession.query(AnggaranOPD).filter_by(id=request.matchdict['id'])
def id_not_found(request):
msg = 'AnggaranOPD ID %s not found.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
@view_config(route_name='anggaran-opd-edit', renderer='templates/anggaran-opd/add.pt',
permission='edit')
def view_edit(request):
row = query_id(request).first()
if not row:
return id_not_found(request)
form = get_form(request, EditSchema)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
c = form.validate(controls)
except ValidationFailure, e:
return dict(form=form)
return HTTPFound(location=request.route_url('anggaran-edit',
id=row.id))
save_request(dict(controls), request, row)
return route_list(request)
elif SESS_EDIT_FAILED in request.session:
del request.session[SESS_EDIT_FAILED]
return dict(form=form)
values = row.to_dict()
values['rekening_kd'] = row.rekenings and row.rekenings.kode or ''
values['rekening_nm'] = row.rekenings and row.rekenings.nama or ''
form.set_appstruct(values)
return dict(form=form)
##########
# Delete #
##########
@view_config(route_name='anggaran-opd-delete', renderer='templates/anggaran-opd/delete.pt',
permission='delete')
def view_delete(request):
q = query_id(request)
row = q.first()
if not row:
return id_not_found(request)
form = Form(colander.Schema(), buttons=('hapus','batal'))
if request.POST:
if 'hapus' in request.POST:
msg = 'AnggaranOPD %s Tahun %s sudah berhasil dihapus.' % (row.kode, row.tahun)
q.delete()
DBSession.flush()
request.session.flash(msg)
return route_list(request)
return dict(row=row,form=form.render())
##########
# Action #
##########
@view_config(route_name='anggaran-opd-act', renderer='json',
permission='read')
def view_act(request):
req = request
params = req.params
url_dict = req.matchdict
if url_dict['act']=='grid':
columns = []
columns.append(ColumnDT('id'))
columns.append(ColumnDT('kode'))
columns.append(ColumnDT('nama'))
columns.append(ColumnDT('nama_unit'))
columns.append(ColumnDT('murni', filter=_DTnumberformat))
columns.append(ColumnDT('perubahan', filter=_DTnumberformat))
columns.append(ColumnDT('tahun'))
columns.append(ColumnDT('status', filter=_DTactive))
query = DBSession.query(AnggaranOPD.id,
AnggaranOPD.kode,
AnggaranOPD.nama,
Unit.nama.label('nama_unit'),
AnggaranOPD.murni,
AnggaranOPD.perubahan,
AnggaranOPD.tahun,
AnggaranOPD.status).\
join(Unit, Unit.id==AnggaranOPD.unit_id).\
order_by(desc(AnggaranOPD.tahun),
AnggaranOPD.kode,
AnggaranOPD.nama
)
rowTable = DataTables(req, AnggaranOPD, query, columns)
return rowTable.output_result()
elif url_dict['act']=='hon':
term = 'term' in params and params['term'] or ''
unit_id = 'unit_id' in params and params['unit_id'] or ''
qry = DBSession.query(AnggaranOPD.id, AnggaranOPD.nama, Rekening.kode).\
join(Rekening).join(UnitRekening).\
filter(AnggaranOPD.status==1)
qry = qry.filter(AnggaranOPD.nama.ilike('%%%s%%' % term))
qry = qry.filter(UnitRekening.unit_id==unit_id)
rows = qry.all()
r = []
for k in rows:
d={}
d['id'] = k[0]
d['value'] = k[1]
d['rekening_kd'] = k[2]
r.append(d)
return r
from ..reports.rml_report import open_rml_row, open_rml_pdf, pdf_response
def query_reg():
return DBSession.query(AnggaranOPD.kode.label('a'),
AnggaranOPD.nama.label('b'),
func.trim(func.to_char(AnggaranOPD.murni,'999,999,999,990')).label('c'),
func.trim(func.to_char(AnggaranOPD.perubahan,'999,999,999,990')).label('d'),
AnggaranOPD.tahun.label('e'),
).order_by(desc(AnggaranOPD.tahun),
AnggaranOPD.kode,
AnggaranOPD.nama
)
########
# CSV #
########
@view_config(route_name='anggaran-opd-csv', renderer='csv')
def view_csv(request):
global unit_id,unit_kd,unit_nm,unit_al
ses = request.session
params = request.params
url_dict = request.matchdict
u = request.user.id
if group_in(request, 'bendahara'):
unit_id = DBSession.query(UserUnit.unit_id
).filter(UserUnit.user_id==u
).first()
unit_id = '%s' % unit_id
unit_id = int(unit_id)
unit = DBSession.query(Unit.kode.label('kode'),
Unit.nama.label('nama'),
Unit.alamat.label('alamat')
).filter(UserUnit.unit_id==unit_id,
Unit.id==unit_id
).first()
unit_kd = '%s' % unit.kode
unit_nm = '%s' % unit.nama
unit_al = '%s' % unit.alamat
if url_dict['csv']=='reg' :
query = query_reg()
if group_in(request, 'bendahara'):
query = query.join(Rekening).join(UnitRekening).\
filter(UnitRekening.unit_id==unit_id)
row = query
header = 'Kode Rekening','Uraian Rekening','Murni','Perubahan','Tahun'
rows = []
for item in row.all():
rows.append(list(item))
# override attributes of response
filename = 'AnggaranOPD_Rekening.csv'
request.response.content_disposition = 'attachment;filename=' + filename
return {
'header': header,
'rows' : rows,
}
##########
# PDF #
##########
@view_config(route_name='anggaran-opd-pdf', permission='read')
def view_pdf(request):
global unit_id,unit_nm,unit_al,unit_kd
params = request.params
url_dict = request.matchdict
u = request.user.id
if group_in(request, 'bendahara'):
unit_id = DBSession.query(UserUnit.unit_id
).filter(UserUnit.user_id==u
).first()
unit_id = '%s' % unit_id
unit_id = int(unit_id)
unit = DBSession.query(Unit.kode.label('kode'),
Unit.nama.label('nama'),
Unit.alamat.label('alamat')
).filter(UserUnit.unit_id==unit_id,
Unit.id==unit_id
).first()
unit_kd = '%s' % unit.kode
unit_nm = '%s' % unit.nama
unit_al = '%s' % unit.alamat
if url_dict['pdf']=='reg' :
nm = "BADAN PENDAPATAN DAERAH"
al = "Jl. Soekarno Hatta, No. 528, Bandung"
query = query_reg()
if group_in(request, 'bendahara'):
query = query.join(Rekening).join(UnitRekening).\
filter(UnitRekening.unit_id==unit_id)
rml_row = open_rml_row('anggaran.row.rml')
rows=[]
for r in query.all():
s = rml_row.format(kode=r.a,
nama=r.b,
murni=r.c,
perubahan=r.d,
tahun=r.e)
rows.append(s)
if group_in(request, 'bendahara'):
pdf, filename = open_rml_pdf('anggaran.rml', rows2=rows,
un_nm=unit_nm,
un_al=unit_al)
else:
pdf, filename = open_rml_pdf('anggaran.rml', rows2=rows,
un_nm=nm,
un_al=al)
return pdf_response(request, pdf, filename)
\ No newline at end of file
......@@ -255,19 +255,25 @@ def save(request, values, row=None):
if not row:
row = ARSspd()
row.create_date = datetime.now(utc)
row.create_uid = request.user.id
row.create_uid = hasattr(request.user,'id') and request.user.id or 1
if 'id' not in request.matchdict:
del values['id']
row.from_dict(values)
row.update_date = datetime.now(utc)
row.update_uid = request.user.id
row.bunga = re.sub("[^0-9]", "", row.bunga)
row.bayar = re.sub("[^0-9]", "", row.bayar)
row.update_uid = hasattr(request.user,'id') and request.user.id or 1
row.bunga = row.bunga and int(re.sub("[^0-9]", "", str(row.bunga))) or 0
row.bayar = row.bayar and int(re.sub("[^0-9]", "", str(row.bayar))) or 0
if not row.tahun_id:
row.tahun_id = datetime.now().strftime('%Y')
##query invoice 27-06-2022
ref = DBSession.query(ARInvoice).\
filter(ARInvoice.kode==values['invoice_no']).\
first()
if not row.pembayaran_ke:
invoice_no = DBSession.query(func.count(ARSspd.arinvoice_id)).\
filter(ARSspd.tahun_id==row.tahun_id,
ARSspd.arinvoice_id==row.arinvoice_id).\
filter(ARSspd.tahun_id==ref.tahun_id,
ARSspd.arinvoice_id==ref.id).\
scalar()
print "--------- Invoice No ---------- ",invoice_no
if not invoice_no:
......@@ -276,9 +282,9 @@ def save(request, values, row=None):
row.pembayaran_ke = invoice_no+1
## -------- Update 29 Agustus 2017 ----------------- ##
ref = DBSession.query(ARInvoice).\
filter(ARInvoice.id==row.arinvoice_id).\
scalar()
# ref = DBSession.query(ARInvoice).\
# filter(ARInvoice.id==row.arinvoice_id).\
# scalar()
row.unit_id = ref.unit_id
row.unit_kode = ref.unit_kode
row.unit_nama = ref.unit_nama
......@@ -291,15 +297,15 @@ def save(request, values, row=None):
DBSession.add(row)
DBSession.flush()
if int(row.bayar)>0:
row.arinvoices.status_bayar=1
row.arinvoices.is_sspd=1
ref.status_bayar=1
ref.is_sspd=1
else:
row.pembayaran_ke = row.pembayaran_ke
row.arinvoices.status_bayar=0
row.arinvoices.is_sspd=0
DBSession.add(row)
ref.status_bayar=0
ref.is_sspd=0
DBSession.add(ref)
DBSession.flush()
return row
setattr(ref, 'status', ref.status_bayar)
return ref
def save_request(values, request, row=None):
if 'id' in request.matchdict:
......
import os
import json
import ast
import uuid
import colander
from datetime import datetime, date, timedelta, time
from sqlalchemy.orm import aliased
from pyramid.view import view_config
from sqlalchemy import not_, func, between, and_, literal_column, case, literal
from pyramid.httpexceptions import HTTPFound
from deform import Form, widget, ValidationFailure
from ..views import ColumnDT, DataTables
from ..models.isipkd import (ARInvoice as ArInvoice, ARSspd as ArPayment, SubjekPajak as Subjek, Unit as Departemen)
from ..models import DBSession
from ..models.bjb_qris import BJBQRIS
from ..tools import (dmy, get_settings, date_from_str,
odt_export, thousand, get_settings, datetime_from_str)
from ..models.rpc import auth_from_rpc
from ..tools import ymd, dmy, ymdhms, dmyhms, dmy_to_date
from pyramid_rpc.jsonrpc import jsonrpc_method
from daftar import hitung_bunga
from arsspd import save as save_payment
SESS_ADD_FAILED = 'Gagal tambah BJBQRIS'
SESS_EDIT_FAILED = 'Gagal edit BJBQRIS'
import logging
log = logging.getLogger('BJBQRIS LOG')
from pyramid.renderers import render_to_response
from sqlalchemy.sql.expression import cast
from sqlalchemy import Integer
def rpc_params():
parameter = dict(
bjbqris_url = get_settings()['bjbqris_url'] and get_settings()['bjbqris_url'].value.strip('/') or '',
bjbqris_user = get_settings()['bjbqris_user'] and get_settings()['bjbqris_user'].value.strip() or '',
bjbqris_key = get_settings()['bjbqris_key'] and get_settings()['bjbqris_key'].value.strip() or ''
)
return parameter
class Item(object):
pass
class AddSchema(colander.Schema):
client_type = colander.SchemaNode(
colander.Integer(),
widget = widget.HiddenWidget(),
default = 3,
oid = "client_type",
title="")
product_code = colander.SchemaNode(
colander.String(),
widget = widget.HiddenWidget(),
default = 30,
oid = "product_code",
title="")
invoice_no = colander.SchemaNode(
colander.String(),
widget=widget.SelectWidget(),
validator=colander.Length(max=16),
oid = "invoice_no",
title="Kode Bayar")
description = colander.SchemaNode(
colander.String(),
widget=widget.TextAreaWidget(rows=6),
validator=colander.Length(max=128),
oid = "description",)
customer_name = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=64),
oid = "customer_name",
title="Customer Name")
customer_email = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=128),
oid = "customer_email",
title="Customer Email")
customer_phone = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=32),
oid = "customer_phone",
title="Customer Phone")
expired_date = colander.SchemaNode(
colander.String(),
widget=widget.TextInputWidget(css_class="input-date"),
oid = "expired_date",
default = ymdhms(datetime.now()),
title="Expired Date")
amount = colander.SchemaNode(
colander.Integer(),
oid = "amount",
title="Amount")
class EditSchema(AddSchema):
invoice_no = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=16),
oid = "invoice_no",
title="Kode Bayar")
billing_type = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=1),
oid = "billing_type",
title="Billing Type")
va_type = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=1),
oid = "va_type",
title="VA Type")
va_number = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "va_number",
title="VA Number")
currency = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "currency",
title="Currency")
customer_id = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "customer_id",
title="Customer ID")
status = colander.SchemaNode(
colander.String(),
missing=colander.drop,
oid = "status",
title="Status")
cin = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=4),
oid = "cin",
title="cin")
response_code = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=4),
oid = "response_code",
title="response_code")
response_message = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=128),
oid = "response_message",
title="response_message")
id = colander.SchemaNode(
colander.Integer(),
missing=colander.drop,
oid='id',
widget=widget.HiddenWidget(readonly=True)
)
def get_form(request, class_form):
schema = class_form()
schema.request = request
return Form(schema, buttons=('simpan','batal'))
def route_list(request):
return HTTPFound(location=request.route_url('bjbqris'))
def session_failed(request, session_name):
r = dict(form=request.session[session_name])
del request.session[session_name]
return r
def query_id(request):
return DBSession.query(BJBQRIS).join(ArInvoice, ArInvoice.kode==BJBQRIS.invoice_no).\
filter(BJBQRIS.id==request.matchdict['id'],
# ArInvoice.departemen_id==request.session['departemen_id']
)
def id_not_found(request):
msg = 'BJBQRIS ID %s not found.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def id_paid(request):
msg = 'BJBQRIS ID %s sudah terbayar.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def id_expired(request):
msg = 'BJBQRIS ID %s expired.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def cekqris(values,request):
cekqris = DBSession.query(BJBQRIS).\
filter(BJBQRIS.invoice_no==values['invoice_no'],BJBQRIS.expired_date>datetime.now()).first()
if cekqris:
msg = 'BJBQRIS No. Billing %s sudah ada.' % cekqris.va_number
request.session.flash(msg, 'error')
raise route_list(request)
###########
# List #
###########
class view(object):
def __init__(self, request):
now = datetime.now()
self.req = request
self.ses = self.req.session
self.params = self.req.params
self.awal = 'awal' in self.ses and self.ses['awal'] or dmy(now)
awal = 'awal' in self.params and self.params['awal'] or self.awal
try:
self.dt_awal = dmy_to_date(awal)
self.awal = awal
except:
self.dt_awal = dmy_to_date(self.awal)
self.ses['awal'] = self.awal
self.ses['dt_awal'] = self.dt_awal
self.akhir = 'akhir' in self.ses and self.ses['akhir'] or dmy(now)
akhir = 'akhir' in self.params and self.params['akhir'] or self.akhir
try:
self.dt_akhir = dmy_to_date(akhir)
self.akhir = akhir
except:
self.dt_akhir = dmy_to_date(self.akhir)
self.ses['akhir'] = self.akhir
self.ses['dt_akhir'] = self.dt_akhir
self.tahun = 'tahun' in self.ses and self.ses['tahun'] or datetime.now().strftime('%Y')
self.tahun = 'tahun' in self.params and self.params['tahun'] or self.tahun
self.ses['tahun'] = self.tahun
@view_config(route_name='bjbqris', renderer='templates/bjbqris/list.pt')
def view_list(self):
return dict()
#########
# Add #
#########
@view_config(route_name='bjbqris-add', renderer='templates/bjbqris/add-edit.pt', permission='add')
def view_add(self):
request = self.req
form = get_form(request, AddSchema)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
return dict(form=form)
cekqris(dict(controls),request)
val = dict(controls)
inv = q_inv(val['invoice_no']).first()
pokok, denda = calculate_tagihan(dict(pokok = inv.jumlah,jatuh_tempo=inv.jatuh_tempo))
val['amount'] = (pokok+denda)
row = BJBQRIS.create_va(val, rpc_params())
if row:
request.session.flash('BJBQRIS No. %s sudah ditambahkan.' % row.va_number)
else:
request.session.flash('BJBQRIS gagal ditambahkan.')
return route_list(request)
return route_list(request)
elif SESS_ADD_FAILED in request.session:
return session_failed(request, SESS_ADD_FAILED)
values = {}
form.set_appstruct(values)
return dict(form=form)
##########
# Action #
##########
@view_config(route_name='bjbqris-act', renderer='json', permission='read')
def view_act(self):
req = self.req
params = req.params
url_dict = req.matchdict
if url_dict['act']=='grid':
columns = [
ColumnDT('id'),
ColumnDT('va_number'),
ColumnDT('invoice_no'),
ColumnDT('description'),
ColumnDT('customer_name'),
ColumnDT('amount'),
ColumnDT('client_refnum'),
ColumnDT('expired_date'),
ColumnDT('tgl_bayar'),
ColumnDT('status'),
]
query = DBSession.query(BJBQRIS.id, BJBQRIS.va_number, BJBQRIS.invoice_no, BJBQRIS.description,
BJBQRIS.customer_name, BJBQRIS.amount, BJBQRIS.client_refnum,
func.to_char(BJBQRIS.expired_date, 'DD-MM-YYYY HH24:MI:SS').label('expired_date'),
func.to_char(ArPayment.tgl_bayar, 'DD-MM-YYYY HH24:MI:SS').label('tgl_bayar'),
ArInvoice.jumlah.label('jml_bayar'),
case([
(BJBQRIS.status == '0', literal('Belum Dibayar'))
],
else_=
case([
(BJBQRIS.status == '1', literal('Dibayar Sebagian'))
],
else_=
case([
(BJBQRIS.status == '2', literal('Dibayar Penuh'))
],
else_=
case([
(BJBQRIS.status == '3', literal('Kadaluarsa'))
],
else_=
case([
(BJBQRIS.status == '4', literal('Disabled'))
],
else_= literal('-')))))).label('status'),
).join(ArInvoice, ArInvoice.kode==BJBQRIS.invoice_no).\
outerjoin(ArPayment, ArInvoice.id==ArPayment.arinvoice_id).\
filter( #ArInvoice.departemen_id==req.session['departemen_id'],
func.to_char(BJBQRIS.created,'YYYY') == str(req.session['tahun']))
rowTable = DataTables(req, BJBQRIS, query, columns)
return rowTable.output_result()
elif url_dict['act'] == 'kodebayar':
term = 'term' in params and params['term'] or ''
q = DBSession.query(ArInvoice). \
filter(ArInvoice.status_bayar == 0,
ArInvoice.kode.ilike('%%%s%%' % term)).\
order_by(ArInvoice.kode)
# filter(ArInvoice.departemen_id==req.session['departemen_id']).\
rows = q.all()
r = []
for k in rows:
d = dict(id=k.id,
value=k.kode,
kode=k.kode,
nama=k.op_nama)
r.append(d)
return r
elif url_dict['act'] == 'detail':
term = 'term' in params and params['term'].strip() or ''
row = q_inv(term).first()
pokok, denda = calculate_tagihan(dict(pokok = row.jumlah,jatuh_tempo=row.jatuh_tempo))
return dict(id=row.id,
value=row.subjek_nama,
description=row.description,
customer_name=row.subjek_nama,
customer_email=row.subjek_email and row.subjek_email or '-',
customer_phone=row.subjek_phone and row.subjek_phone or '-',
expired_date=ymdhms(datetime.combine(date.today(),time(23,59,59))),
amount=(pokok + denda))
elif url_dict['act'] == 'qrcode':
id = 'id' in params and params['id'] or ''
qr = ''
if id:
qris = BJBQRIS.query_id(id).first()
import qrcode
from ..tools import get_tmp
img = qrcode.make(str(qris.qrcode))
path = get_tmp() + str(qris.va_number)
img.save(path, 'PNG')
qr = path+'PNG'
import base64
qr = base64.b64encode(open(path, 'rb').read())
from pyramid.renderers import render_to_response
return render_to_response("templates/bjbqris/qrcode.pt", dict(qr=qr))
@jsonrpc_method(method='callback', endpoint='bjbqris-callback')
def callback(request, data):
##
## CALLBACK BODY
## {
## "data": {
## "invoice_no": "230001",
## "va_number": "00170743733",
## "transaction_date": "2021-08-19 10:08:30",
## "transaction_amount": 526829,
## "unpaid": 0,
## "status": 2
## }
## }
##
auth_from_rpc(request)
log.error('REQUEST BJBQRIS')
log.error(data)
get_va = BJBQRIS.query().filter(BJBQRIS.va_number==data['va_number'],
BJBQRIS.invoice_no==data['invoice_no']).first()
if not get_va:
return render_to_response('json',
dict(response_code='-1',response_message='VA Number not Found'))
get_va.status = 'status' in data and data['status']\
and str(data['status']) or get_va.status
get_va.transaction_amount = 'transaction_amount' in data and data['transaction_amount']\
and data['transaction_amount'] or get_va.amount
get_va.transaction_date = 'transaction_date' in data and data['transaction_date']\
and data['transaction_date'] or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
pay = save_pembayaran(
request,
dict(
invoice_no = get_va.invoice_no,
va_number = get_va.va_number,
transaction_date = get_va.transaction_date,
transaction_amount = get_va.transaction_amount,
status = get_va.status,
amount = get_va.amount
)
)
if not pay:
return render_to_response('json',
dict(response_code='-1',response_message='Failed to update'))
if int(get_va.status) == 2 and not pay.status:
get_va.status = '1'
try:
DBSession.add(get_va)
DBSession.flush()
return render_to_response('json',
dict(response_code='0000',response_message='Success'))
except:
return render_to_response('json',
dict(response_code='-1',response_message='Failed to update'))
def save_pembayaran(request, values):
if int(values['status']) not in [1,2]:
return
invoice = ArInvoice.query().filter(ArInvoice.kode==values['invoice_no']).first()
if not invoice:
return
values.update(invoice.to_dict())
values['tgl_bayar'] = datetime_from_str(values['transaction_date'])
values['ntb'] = 'BJBQRIS'
values['bayar'] = int(values['transaction_amount'])
values['tahun'] = values['tgl_bayar'].strftime('%Y')
values['status'] = 2
pay = save_payment(request, values)
return pay
def q_inv(kode):
return DBSession.query(ArInvoice.id.label('id'),
ArInvoice.jumlah.label('jumlah'),
ArInvoice.kode.label('kode'),
ArInvoice.jatuh_tempo.label('jatuh_tempo'),
func.concat(ArInvoice.no_skrd ,
literal_column("' Tgl:'") ,
func.to_char(ArInvoice.tgl_tetap, 'DD/MM/YYYY') ,
literal_column("' Jatuh Tempo:'") ,
func.to_char(ArInvoice.jatuh_tempo, 'DD/MM/YYYY') ,
literal_column("' '") ,
ArInvoice.keterangan).label('description'),
ArInvoice.wp_nama.label('subjek_nama'),
Subjek.email.label('subjek_email'),
literal_column("'-'").label('subjek_phone')).\
filter(ArInvoice.status_bayar == 0,ArInvoice.kode == kode).\
outerjoin(Subjek, Subjek.id==ArInvoice.subjek_pajak_id)
# filter(ArInvoice.departemen_id==req.session['departemen_id']).\
def calculate_tagihan(values):
pokok = int(values['pokok'])
denda = hitung_bunga(pokok,values['jatuh_tempo'])
return pokok, denda
\ No newline at end of file
import os
import json
import ast
import uuid
import colander
from datetime import datetime, date, timedelta, time
from sqlalchemy.orm import aliased
from pyramid.view import view_config
from sqlalchemy import not_, func, between, and_, literal_column, case, literal
from pyramid.httpexceptions import HTTPFound
from deform import Form, widget, ValidationFailure
from ..views import ColumnDT, DataTables
from ..models.isipkd import (ARInvoice as ArInvoice, ARSspd as ArPayment, SubjekPajak as Subjek, Unit as Departemen)
from ..models import DBSession
from ..models.bjb_va import BJBVA
from ..tools import (dmy, get_settings, date_from_str,
odt_export, thousand, get_settings, datetime_from_str)
from ..models.rpc import auth_from_rpc
from ..tools import ymd, dmy, ymdhms, dmyhms, dmy_to_date
from pyramid_rpc.jsonrpc import jsonrpc_method
from daftar import hitung_bunga
from arsspd import save as save_payment
SESS_ADD_FAILED = 'Gagal tambah BJBVA'
SESS_EDIT_FAILED = 'Gagal edit BJBVA'
import logging
log = logging.getLogger('BJBVA LOG')
from pyramid.renderers import render_to_response
from sqlalchemy.sql.expression import cast
from sqlalchemy import Integer
def rpc_params():
parameter = dict(
bjbva_url = get_settings()['bjbva_url'] and get_settings()['bjbva_url'].value.strip('/') or '',
bjbva_user = get_settings()['bjbva_user'] and get_settings()['bjbva_user'].value.strip() or '',
bjbva_key = get_settings()['bjbva_key'] and get_settings()['bjbva_key'].value.strip() or ''
)
return parameter
class Item(object):
pass
class AddSchema(colander.Schema):
client_type = colander.SchemaNode(
colander.Integer(),
widget = widget.HiddenWidget(),
default = 3,
oid = "client_type",
title="")
product_code = colander.SchemaNode(
colander.String(),
widget = widget.HiddenWidget(),
default = 30,
oid = "product_code",
title="")
invoice_no = colander.SchemaNode(
colander.String(),
widget=widget.SelectWidget(),
validator=colander.Length(max=16),
oid = "invoice_no",
title="Kode Bayar")
description = colander.SchemaNode(
colander.String(),
widget=widget.TextAreaWidget(rows=6),
validator=colander.Length(max=128),
oid = "description",)
customer_name = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=64),
oid = "customer_name",
title="Customer Name")
customer_email = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=128),
oid = "customer_email",
title="Customer Email")
customer_phone = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=32),
oid = "customer_phone",
title="Customer Phone")
expired_date = colander.SchemaNode(
colander.String(),
widget=widget.TextInputWidget(css_class="input-date"),
oid = "expired_date",
default = ymdhms(datetime.now()),
title="Expired Date")
amount = colander.SchemaNode(
colander.Integer(),
oid = "amount",
title="Amount")
class EditSchema(AddSchema):
invoice_no = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=16),
oid = "invoice_no",
title="Kode Bayar")
billing_type = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=1),
oid = "billing_type",
title="Billing Type")
va_type = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=1),
oid = "va_type",
title="VA Type")
va_number = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "va_number",
title="VA Number")
currency = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "currency",
title="Currency")
customer_id = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=32),
oid = "customer_id",
title="Customer ID")
status = colander.SchemaNode(
colander.String(),
missing=colander.drop,
oid = "status",
title="Status")
cin = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=4),
oid = "cin",
title="cin")
response_code = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=4),
oid = "response_code",
title="response_code")
response_message = colander.SchemaNode(
colander.String(),
missing=colander.drop,
validator=colander.Length(max=128),
oid = "response_message",
title="response_message")
id = colander.SchemaNode(
colander.Integer(),
missing=colander.drop,
oid='id',
widget=widget.HiddenWidget(readonly=True)
)
def get_form(request, class_form):
schema = class_form()
schema.request = request
return Form(schema, buttons=('simpan','batal'))
def route_list(request):
return HTTPFound(location=request.route_url('bjbva'))
def session_failed(request, session_name):
r = dict(form=request.session[session_name])
del request.session[session_name]
return r
def query_id(request):
return DBSession.query(BJBVA).join(ArInvoice, ArInvoice.kode==BJBVA.invoice_no).\
filter(BJBVA.id==request.matchdict['id'])
# ArInvoice.departemen_id==request.session['departemen_id'])
def id_not_found(request):
msg = 'BJBVA ID %s not found.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def id_paid(request):
msg = 'BJBVA ID %s sudah terbayar.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def id_expired(request):
msg = 'BJBVA ID %s expired.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def cekva(values,request):
cekva = DBSession.query(BJBVA).\
filter(BJBVA.invoice_no==values['invoice_no'],BJBVA.expired_date>datetime.now()).first()
if cekva:
msg = 'BJBVA No. VA %s sudah ada.' % cekva.va_number
request.session.flash(msg, 'error')
raise route_list(request)
###########
# List #
###########
class view(object):
def __init__(self, request):
now = datetime.now()
self.req = request
self.ses = self.req.session
self.params = self.req.params
self.awal = 'awal' in self.ses and self.ses['awal'] or dmy(now)
awal = 'awal' in self.params and self.params['awal'] or self.awal
try:
self.dt_awal = dmy_to_date(awal)
self.awal = awal
except:
self.dt_awal = dmy_to_date(self.awal)
self.ses['awal'] = self.awal
self.ses['dt_awal'] = self.dt_awal
self.akhir = 'akhir' in self.ses and self.ses['akhir'] or dmy(now)
akhir = 'akhir' in self.params and self.params['akhir'] or self.akhir
try:
self.dt_akhir = dmy_to_date(akhir)
self.akhir = akhir
except:
self.dt_akhir = dmy_to_date(self.akhir)
self.ses['akhir'] = self.akhir
self.ses['dt_akhir'] = self.dt_akhir
self.tahun = 'tahun' in self.ses and self.ses['tahun'] or datetime.now().strftime('%Y')
self.tahun = 'tahun' in self.params and self.params['tahun'] or self.tahun
self.ses['tahun'] = self.tahun
@view_config(route_name='bjbva', renderer='templates/bjbva/list.pt')
def view_list(self):
return dict()
#########
# Add #
#########
@view_config(route_name='bjbva-add', renderer='templates/bjbva/add-edit.pt', permission='read')
def view_add(self):
request = self.req
form = get_form(request, AddSchema)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
return dict(form=form)
cekva(dict(controls),request)
val = dict(controls)
inv = q_inv(val['invoice_no']).first()
pokok, denda = calculate_tagihan(dict(pokok = inv.jumlah,jatuh_tempo=inv.jatuh_tempo))
val['amount'] = (pokok+denda)
row = BJBVA.create_va(val, rpc_params())
if row:
request.session.flash('BJBVA No. %s sudah ditambahkan.' % row.va_number)
else:
request.session.flash('BJBVA gagal ditambahkan.')
return route_list(request)
return route_list(request)
elif SESS_ADD_FAILED in request.session:
return session_failed(request, SESS_ADD_FAILED)
values = {}
form.set_appstruct(values)
return dict(form=form)
########
# Edit #
########
@view_config(route_name='bjbva-edt', renderer='templates/bjbva/add-edit.pt', permission='edit')
def view_edit(self):
request = self.req
form = get_form(request, EditSchema)
row = query_id(request).first()
if not row or int(row.status) == 4:
return id_not_found(request)
if int(row.status) in [1,2]:
return id_paid(request)
if int(row.status) == 3:
return id_expired(request)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
return dict(form=form)
save = BJBVA.update_va(dict(controls), row, rpc_params())
if save:
request.session.flash('BJBVA No. %s sudah ditambahkan.' % save.va_number)
else:
request.session.flash('BJBVA gagal ditambahkan.')
return route_list(request)
return route_list(request)
elif SESS_EDIT_FAILED in request.session:
return session_failed(request, SESS_EDIT_FAILED)
values = row.to_dict()
values['expired_date'] = ymdhms(values['expired_date'])
inv = q_inv(values['invoice_no']).first()
pokok, denda = calculate_tagihan(dict(pokok = inv.jumlah,jatuh_tempo=inv.jatuh_tempo))
values['amount'] = (pokok+denda)
form.set_appstruct(values)
return dict(form=form)
##########
# Delete #
##########
@view_config(route_name='bjbva-del', renderer='templates/bjbva/delete.pt', permission='delete')
def view_delete(self):
request = self.req
row = query_id(request).first()
if not row or int(row.status) == 4:
return id_not_found(request)
if int(row.status) in [1,2]:
return id_paid(request)
if int(row.status) == 3:
return id_expired(request)
form = Form(colander.Schema(), buttons=('hapus','batal'))
if request.POST:
if 'hapus' in request.POST:
save = BJBVA.cancel_va(row.to_dict(), rpc_params())
if save:
request.session.flash('BJBVA No. %s sudah dihapus.' % save.va_number)
else:
request.session.flash('BJBVA gagal dihapus.')
DBSession.flush()
return route_list(request)
return dict(row=row, form=form.render())
##########
# Action #
##########
@view_config(route_name='bjbva-act', renderer='json', permission='read')
def view_act(self):
req = self.req
params = req.params
url_dict = req.matchdict
if url_dict['act']=='grid':
columns = [
ColumnDT('id'),
ColumnDT('va_number'),
ColumnDT('invoice_no'),
ColumnDT('description'),
ColumnDT('customer_name'),
ColumnDT('amount'),
ColumnDT('client_refnum'),
ColumnDT('expired_date'),
ColumnDT('tgl_bayar'),
ColumnDT('status'),
]
query = DBSession.query(BJBVA.id, BJBVA.va_number, BJBVA.invoice_no, BJBVA.description,
BJBVA.customer_name, BJBVA.amount, BJBVA.client_refnum,
func.to_char(BJBVA.expired_date, 'DD-MM-YYYY HH24:MI:SS').label('expired_date'),
func.to_char(ArPayment.tgl_bayar, 'DD-MM-YYYY HH24:MI:SS').label('tgl_bayar'),
ArInvoice.jumlah.label('jml_bayar'),
case([
(BJBVA.status == '0', literal('Belum Dibayar'))
],
else_=
case([
(BJBVA.status == '1', literal('Dibayar Sebagian'))
],
else_=
case([
(BJBVA.status == '2', literal('Dibayar Penuh'))
],
else_=
case([
(BJBVA.status == '3', literal('Kadaluarsa'))
],
else_=
case([
(BJBVA.status == '4', literal('Disabled'))
],
else_= literal('-')))))).label('status'),
).join(ArInvoice, ArInvoice.kode==BJBVA.invoice_no).\
outerjoin(ArPayment, ArInvoice.id==ArPayment.arinvoice_id).\
filter( #ArInvoice.departemen_id==req.session['departemen_id'],
func.to_char(BJBVA.created,'YYYY') == str(req.session['tahun']))
rowTable = DataTables(req, BJBVA, query, columns)
return rowTable.output_result()
elif url_dict['act'] == 'kodebayar':
term = 'term' in params and params['term'] or ''
q = DBSession.query(ArInvoice). \
filter(ArInvoice.status_bayar == 0,
ArInvoice.kode.ilike('%%%s%%' % term)).\
order_by(ArInvoice.kode)
# filter(ArInvoice.departemen_id==req.session['departemen_id']).\
rows = q.all()
r = []
for k in rows:
d = dict(id=k.id,
value=k.kode,
kode=k.kode,
nama=k.op_nama)
r.append(d)
return r
elif url_dict['act'] == 'detail':
term = 'term' in params and params['term'].strip() or ''
row = q_inv(term).first()
pokok, denda = calculate_tagihan(dict(pokok = row.jumlah,jatuh_tempo=row.jatuh_tempo))
return dict(id=row.id,
value=row.subjek_nama,
description=row.description,
customer_name=row.subjek_nama,
customer_email=row.subjek_email and row.subjek_email or '-',
customer_phone=row.subjek_phone and row.subjek_phone or '-',
expired_date=ymdhms(datetime.combine(date.today(),time(23,59,59))),
amount=(pokok + denda))
elif url_dict['act'] == 'update':
term = 'term' in params and params['term'] or ''
if term:
va = DBSession.query(BJBVA).join(ArInvoice, ArInvoice.kode==BJBVA.invoice_no).\
filter(BJBVA.id==term, ArInvoice.status_bayar==0).first()
if va:
update_va(req, va, rpc_params())
elif url_dict['act'] == 'cron':
vas = DBSession.query(BJBVA).select_from(BJBVA).join(ArInvoice, ArInvoice.kode==BJBVA.invoice_no).\
join(ArPayment, ArPayment.arinvoice_id == ArInvoice.id).\
filter(BJBVA.status=='0',ArInvoice.status_bayar==1).all()
for va in vas:
values = va.to_dict()
BJBVA.cancel_va(values, rpc_params())
@jsonrpc_method(method='callback', endpoint='bjbva-callback')
def callback(request, data):
##
## CALLBACK BODY
## {
## "data": {
## "invoice_no": "230001",
## "va_number": "00170743733",
## "transaction_date": "2021-08-19 10:08:30",
## "transaction_amount": 526829,
## "unpaid": 0,
## "status": 2
## }
## }
##
auth_from_rpc(request)
log.error('REQUEST BJBVA')
log.error(data)
get_va = BJBVA.query().filter(BJBVA.va_number==data['va_number'],
BJBVA.invoice_no==data['invoice_no']).first()
if not get_va:
return render_to_response('json',
dict(response_code='-1',response_message='VA Number not Found'))
get_va.status = 'status' in data and data['status']\
and str(data['status']) or get_va.status
get_va.transaction_amount = 'transaction_amount' in data and data['transaction_amount']\
and data['transaction_amount'] or get_va.amount
get_va.transaction_date = 'transaction_date' in data and data['transaction_date']\
and data['transaction_date'] or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
pay = save_pembayaran(
request,
dict(
invoice_no = get_va.invoice_no,
va_number = get_va.va_number,
transaction_date = get_va.transaction_date,
transaction_amount = get_va.transaction_amount,
status = get_va.status,
amount = get_va.amount
)
)
if not pay:
return render_to_response('json',
dict(response_code='-1',response_message='Failed to update'))
if int(get_va.status) == 2 and not pay.status:
get_va.status = '1'
try:
DBSession.add(get_va)
DBSession.flush()
return render_to_response('json',
dict(response_code='0000',response_message='Success'))
except:
return render_to_response('json',
dict(response_code='-1',response_message='Failed to update'))
def update_va(request,row, parameter):
saved_va = BJBVA.inquiry_va(row, parameter)
if hasattr(saved_va,'status') and saved_va.status and int(saved_va.status) in [1,2]:
save_pembayaran(
request,
dict(
invoice_no = saved_va.invoice_no,
va_number = saved_va.va_number,
transaction_date = ymdhms(saved_va.transaction_date),
transaction_amount = saved_va.transaction_amount,
status = saved_va.status,
)
)
def save_pembayaran(request, values):
if int(values['status']) not in [1,2]:
return
invoice = ArInvoice.query().filter(ArInvoice.kode==values['invoice_no']).first()
if not invoice:
return
values.update(invoice.to_dict())
values['tgl_bayar'] = datetime_from_str(values['transaction_date'])
values['ntb'] = 'BJBVA'
values['bayar'] = int(values['transaction_amount'])
values['tahun'] = values['tgl_bayar'].strftime('%Y')
values['status'] = 2
pay = save_payment(request, values)
return pay
def q_inv(kode):
return DBSession.query(ArInvoice.id.label('id'),
ArInvoice.jumlah.label('jumlah'),
ArInvoice.kode.label('kode'),
ArInvoice.jatuh_tempo.label('jatuh_tempo'),
func.concat(ArInvoice.no_skrd ,
literal_column("' Tgl:'") ,
func.to_char(ArInvoice.tgl_tetap, 'DD/MM/YYYY') ,
literal_column("' Jatuh Tempo:'") ,
func.to_char(ArInvoice.jatuh_tempo, 'DD/MM/YYYY') ,
literal_column("' '") ,
ArInvoice.keterangan).label('description'),
ArInvoice.wp_nama.label('subjek_nama'),
Subjek.email.label('subjek_email'),
literal_column("'-'").label('subjek_phone')).\
filter(ArInvoice.status_bayar == 0,ArInvoice.kode == kode).\
outerjoin(Subjek, Subjek.id==ArInvoice.subjek_pajak_id)
def calculate_tagihan(values):
pokok = int(values['pokok'])
denda = hitung_bunga(pokok,values['jatuh_tempo'])
return pokok, denda
\ No newline at end of file
......@@ -13,118 +13,10 @@ from ..tools import (date_from_str, dict_to_str, to_str, get_settings)
from ..models.isipkd import (DBSession, ARInvoice, ARSspd, User, Unit,
ObjekPajak, SubjekPajak, Rekening, Wilayah)
from .arinvoice import save as save_invoice
from ..models.rpc import DepartemenRoute
from ..models.rpc import DepartemenRoute, auth_from_rpc
import logging
log = logging.getLogger(__name__)
log = logging.getLogger('RPC ESIPKD')
now = datetime.now()
datenow = now.date()
lima_menit = 600
####################### API TOOL #######################################
def auth_from_rpc(request):
settings = get_settings()
env = request.environ
if not ('HTTP_USERID' in env and 'HTTP_SIGNATURE' in env and
'HTTP_KEY' in env):
raise JsonRpcInvalidLoginError
http_userid = env['HTTP_USERID']
q = DBSession.query(User).filter_by(user_name=http_userid)
user = q.first()
if not user or user.status == 0:
raise JsonRpcInvalidLoginError
# bypass cek authentication for development
if http_userid=='admin' and 'devel' in settings and settings['devel']:
return user
time_stamp = int(env['HTTP_KEY'])
now = get_seconds()
if (not 'devel' in settings or not settings['devel']) and abs(now - time_stamp) > lima_menit:
raise JsonRpcInvalidTimeError
header = json_rpc_header(http_userid, user.api_key, time_stamp)
if header['signature'] != env['HTTP_SIGNATURE']:
raise JsonRpcInvalidLoginError
return user
def json_rpc_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', '')
return dict(userid=userid, signature=encoded_signature, key=time_stamp)
def get_jsonrpc(method, params):
return dict(jsonrpc='2.0', method=method, params=params, id=get_random_number(6))
class JsonRpcInvalidTimeError(JsonRpcError):
code = -41014
message = 'Periksa Date Time Server'
class JsonRpcInvalidLoginError(JsonRpcError):
code = -41001
message = "Invalid RPC User/Password"
class JsonRpcInvalidDataError(JsonRpcError):
code = -41005
message = 'Data Tidak Valid'
class JsonRpcBillNotFoundError(JsonRpcError):
code = -52001
message = 'Bill Not Found'
class JsonRpcBillAllreadyPaidError(JsonRpcError):
code = -52002
message = 'Bill Allready Paid'
class JsonRpcPaymentNotFoundError(JsonRpcError):
code = -54001
message = 'Payment Not Found'
def custom_error(code, message):
cls = JsonRpcError()
cls.code = code
cls.message = message
cls.message = message
raise cls
def get_mandatory(data, values):
for value in values:
if not value in data or not data[value]:
raise JsonRpcInvalidDataError(message="{} Not Found".format(value))
def get_seconds():
begin_unix_time = datetime(1970, 1, 1)
durasi = datetime.utcnow() - begin_unix_time
return int(durasi.total_seconds())
def get_random_number(width=12):
return ''.join(choice(digits) \
for _ in range(width))
def clear_null_value(values):
# digunakan untuk menghapus dictionary yang value nya null
tobe_del = []
for value in values:
if not values[value]:
tobe_del.append(value)
for value in tobe_del:
del values[value]
return values
def ymd(tgl):
return tgl.strftime('%Y-%m-%d')
###########################################################################
......
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content" class="form-550">
<h4>Tambah/Edit Anggaran OPD</h4>
<hr>
<!--div tal:content="structure form"/-->
<form id="deform" method="POST" enctype="multipart/form-data" accept-charset="utf-8"
class="form-horizontal">
<fieldset class="deformFormFieldset">
<input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="deform"/>
<div class="form-group">
<div tal:condition="'id' in form">
<div tal:define="field form['id']">
${structure:field.serialize()}
</div>
</div>
<div tal:define="field form['kode']">
${structure:field.serialize()}
</div>
<div tal:define="field form['nama']">
${structure:field.serialize()}
</div>
<!--rekening_id -->
<div tal:define="field form['rekening_id']">
${structure:field.serialize()}
</div>
<div class="col-md-12">
<!--rekening-->
<div class="form-group" tal:define="field form['rekening_kd']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9" tal:define="field form['rekening_kd']" >
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<div class="form-group" tal:define="field form['rekening_nm']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9" tal:define="field form['rekening_nm']" >
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--opd-->
<div class="form-group" tal:define="field form['unit_id']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9" tal:define="field form['unit_id']" >
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--murni -->
<div class="form-group" tal:define="field form['murni']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--perubahan -->
<div class="form-group" tal:define="field form['perubahan']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--tahun -->
<div class="form-group" tal:define="field form['tahun']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--status -->
<div class="form-group" tal:define="field form['status']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--Button -->
<div class="form-group">
<label class="control-label col-md-3">
</label>
<div class="col-md-9">
<button id="deformsave" name="simpan" type="submit" class="btn btn-primary "
value="simpan">Simpan</button>
<button id="deformcancel" name="cancel" type="submit" class="btn btn-danger "
value="cancel">Batal</button>
</div>
</div>
</div>
</div>
<script>
$('#rekening_kd').typeahead({
"hint" : true,
"highlight": true,
"minLength": 1,
"limit" : 20,
"remote" : "/rekening/hok_anggaran/act?term=%QUERY",
},{
"name" : 'rekening_kd',
"displayKey": 'value',
});
$('#rekening_kd').bind('typeahead:selected', function(obj, datum, name) {
$('#rekening_id').val(datum.id);
$('#rekening_nm').val(datum.nama);
$('#kode').val(datum.value);
$('#nama').val(datum.nama);
});
$('#rekening_nm').typeahead({
"hint" : true,
"highlight": true,
"minLength": 1,
"limit" : 20,
"remote" : "/rekening/hon_anggaran/act?term=%QUERY",
},{
"name" : 'rekening_nm',
"displayKey": 'value',
});
$('#rekening_nm').bind('typeahead:selected', function(obj, datum, name) {
$('#rekening_id').val(datum.id);
$('#rekening_kd').val(datum.kode);
$('#kode').val(datum.kode);
$('#nama').val(datum.value);
});
$('#murni').keyup(function(){
var murni = this.value.length;
});
$('#perubahan').keyup(function(){
var perubahan = this.value.length;
});
</script>
</fieldset>
</form>
</div>
</html>
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Warning</h3>
</div>
<div class="panel-body">
Hapus anggaran rekening ${row.kode} ${row.nama} tahun ${row.tahun} ?
</div>
</div>
<div tal:content="structure form"/>
</div>
</html>
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content" class="form-550">
<h4>Edit Tarif</h4>
<hr>
<!--div tal:content="structure form"/-->
<form id="deform" method="POST" enctype="multipart/form-data" accept-charset="utf-8"
class="form-horizontal">
<fieldset class="deformFormFieldset">
<input type="hidden" name="_charset_" />
<input type="hidden" name="__formid__" value="deform"/>
<div class="form-group">
<div tal:condition="'id' in form">
<div tal:define="field form['id']">
${structure:field.serialize()}
</div>
</div>
<div class="col-md-12">
<!--kode -->
<div class="form-group" tal:define="field form['kode']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--nama -->
<div class="form-group" tal:define="field form['nama']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--rekening_id -->
<div class="form-group" tal:define="field form['rekening_id']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9" tal:define="field form['rekening_id']" >
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--tahun -->
<div class="form-group" tal:define="field form['tahun']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--tarif -->
<div class="form-group" tal:define="field form['tarif']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--status -->
<div class="form-group" tal:define="field form['status']" id="item-${field.oid}">
<label for="${field.oid}" class="control-label col-md-3" id="req-${field.oid}">
${field.title}<span id="error-${field.oid}" class="text text-danger"
tal:condition="field.required">&nbsp*</span></label>
<div class="col-md-9">
${structure:field.serialize()}
<p id="error-${field.oid}" class="help-block" tal:condition="field.error"
tal:repeat="error field.error.messages()">
${error}</p>
</div>
</div>
<!--Button -->
<div class="form-group">
<label class="control-label col-md-3">
</label>
<div class="col-md-9">
<button id="deformsave" name="simpan" type="submit" class="btn btn-primary "
value="simpan">Simpan</button>
<button id="deformcancel" name="cancel" type="submit" class="btn btn-danger "
value="cancel">Batal</button>
</div>
</div>
</div>
</div>
</fieldset>
</form>
</div>
</html>
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<link href="/static/datatables/extensions/TableTools/css/dataTables.tableTools.min.css" rel="stylesheet">
<link href="/static/datatables/media/css/dataTables.bootstrap.css" rel="stylesheet">
<h4>Anggaran OPD</h4>
<hr>
<table id="table1" name="table1" class="table table-bordered table-hover table-condensed" >
<thead>
<tr>
<th>ID</th>
<th>Kode Rekening</th>
<th>Uraian Rekening</th>
<th>Unit Kerja/OPD</th>
<th>Murni</th>
<th>Perubahan</th>
<th>Tahun</th>
<th>Status</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script src="/static/datatables/media/js/jquery.dataTables.min.js"></script>
<!--script src="/static/datatables/media/js/jquery.jeditable.js')}"></script-->
<script src="/static/datatables/media/js/jquery.dataTables.ext.js"></script>
<script src="/static/datatables/extensions/TableTools/media/js/ZeroClipboard.js"></script>
<script src="/static/datatables/media/js/dataTables.bootstrap.js"></script>
<script>
var mID;
var oTable;
var iPos;
var oFormUrl = "/anggaran/opd/";
var oTableUrl = oFormUrl+"grid/act";
$(document).ready(function () {
oTable = $('#table1').dataTable({
"sAjaxSource" : oTableUrl,
"bStateSave" : true,
"bServerSide" : true,
"bProcessing" : true,
"sDom" : '<"toolbar">lfrtip',
"bScrollCollapse" : true,
"bSort" : true,
"bInfo" : false,
"bFilter" : true,
"bAutoWidth" : false,
"bPaginate" : true,
"sPaginationType" : "full_numbers",
"lengthMenu": [
[10, 25, 50, 100, 150, 200],
[10, 25, 50, 100, 150, 200]
],
"aoColumnDefs": [
{"bSearchable": false,
"bVisible" : false,
"aTargets" : [0]
}
],
"aoColumns": [
null,
{"sWidth": "100px", "sClass": "left"},
{"sWidth": "250px", "sClass": "left"},
{"sWidth": "250px", "sClass": "left"},
{"sWidth": "50px", "sClass": "right"},
{"sWidth": "50px", "sClass": "right"},
{"sWidth": "30px", "sClass": "center"},
{"sWidth": "40px", "sClass": "center"}
],
"language": {
"search" : "Cari: ",
"paginate":{
"first" : "Pertama ",
"last" : "Terakhir ",
"previous": "Sebelumnya ",
"next" : "Selanjutnya ",
},
"lengthMenu" : "Tampil _MENU_ baris "
}
});
var tb_array = [
'<div class="btn-group pull-left">',
' <button id="btn_tambah" class="btn btn btn-primary pull-left" type="button">Tambah</button>',
' <button id="btn_edit" class="btn btn btn-primary pull-left" type="button">Edit</button>',
' <button id="btn_delete" class="btn btn btn-danger pull-left" type="button">Hapus</button>',
//' <button id="btn_print" class="btn btn btn-primary pull-left" type="button">Cetak</button>',
' <button id="btn_pdf" class="btn btn btn-success pull-left" type="button">PDF</button>',
' <button id="btn_csv" class="btn btn btn-info pull-left" type="button">CSV</button>',
' <button id="btn_close" class="btn btn btn-warning" type="button">Tutup</button>',
' &nbsp;',
'</div>',
];
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$('#table1 tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
mID = '';
$(this).removeClass('selected');
} else {
iPos = oTable.fnGetPosition(this);
var aData = oTable.fnGetData(iPos);
mID = aData[0];
oTable.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
}
});
$('#btn_tambah').click(function () {
window.location = oFormUrl+'add';
});
$('#btn_edit').click(function () {
if (mID) {
window.location = oFormUrl+mID+'/edit';
} else {
alert('Silahkan pilih data yang akan diedit');
}
});
$('#btn_print').click(function () {
url = "/reports/act/rAnggaran"
window.open(url);
});
$('#btn_pdf').click(function () {
url = oFormUrl+"reg/pdf";
window.open(url);
});
$('#btn_csv').click(function () {
url = oFormUrl+"reg/csv";
window.open(url);
});
$('#btn_close').click(function () {
window.location = "/"
});
$('#btn_delete').click(function () {
if (mID) {
var hapus = confirm('Hapus data ini?');
if (hapus == true) {
window.location = oFormUrl+mID+'/delete';
};
} else {
alert('Silahkan pilih data yang akan dihapus');
}
});
});
</script>
</div>
</html>
\ No newline at end of file
......@@ -82,6 +82,13 @@
</li>
<!--li tal:attributes="class request.path == '/arsspd' and 'active'"><a href="/arsspd">Penerimaan</a></li-->
<li tal:attributes="class request.path == '/arsts' and 'active'"><a href="/arsts">STS</a></li>
<li class="dropdown" tal:attributes="class request.matched_route.name in ['bjbva','bjbva-add','bjbva-edt','bjbva-del','bjbva-act','bjbva-callback','bjbqris','bjbqris-add','bjbqris-act','bjbqris-callback'] and 'active'">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">BJB<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/bjbva">BJB VA</a></li>
<li><a href="/bjbqris">BJB QRIS</a></li>
</ul>
</li>
<!--li tal:attributes="class request.path == '/pbbkb' and 'active'"><a href="/pbbkb">PBB-KB</a></li>
......@@ -106,6 +113,7 @@
<li><a href="/rekening">Kode Rekening</a></li>
<li><a href="/pajak">Tarif</a></li>
<li><a href="/anggaran">Anggaran</a></li>
<li><a href="/anggaran/opd">Anggaran-OPD</a></li>
<li><a href="/wilayah">Wilayah</a></li>
<li><a href="/sptpd/sektor">Sektor PBBKB</a></li>
<li><a href="/sptpd/peruntukan">Peruntukan PBBKB</a></li>
......
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<div class="panel panel-default">
<div class="panel-body">
<form id="cariform" method="POST" enctype="multipart/form-data" accept-charset="utf-8" class="form-horizontal">
<div class="alert alert-danger" tal:condition="form and form.error and True or False">
<div class="error-msg-lbl">Kesalahan Pengisian Form</div>
<p class="error-msg">${form.errormsg}</p>
</div>
<div class="form-group" tal:repeat="f form">
<div id="item-${f.oid}" style="${f.widget.hidden and 'display:none;' or 'display:block;'}">
<label for="${f.oid}" class="control-label col-md-2 ${f.required and 'required' or ''} " id="req-${f.oid}">
${f.title}</label>
<div class="col-md-3">
${structure:f.serialize()}
<p id="error-${f.oid}" class="help-block" tal:condition="f.error"
tal:repeat="error f.error.messages()">
${error}</p>
</div>
</div>
</div>
<div class="col-md-4">
<label class="control-label col-md-3"></label>
<button type="submit" class="btn btn-primary" id="simpan" name="simpan">Simpan</button>
<button type="submit" class="btn btn-warning" id="batal" name="batal">Tutup</button>
</div>
</form>
</div> <!--panel-body-->
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.4.4/js/bootstrap-datetimepicker.min.js" integrity="sha512-4lTnmq2kNbykTiOPulgEvxRgqegB5/YMhMqaBWvxji/9wRgR9W/TSGF51/mIG1hQ6janxTojpr41y5/gaW9LRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.4.4/css/bootstrap-datetimepicker.min.css" integrity="sha512-m9g5oqvMhf2FsilNZqftBnOR1GW+dJpb1a8RN+R3Aw1dVI2AeDfpSOa9Sm48xMacONC1vJlM2iIadPy4uLEC4Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function () {
function formatNumber(toFormat) {
return toFormat.toString().replace(
/\B(?=(\d{3})+(?!\d))/g, "."
);
};
$('.input-date').datetimepicker({
format: "yyyy-mm-dd hh:ii:ss"
});
<tal:block tal:condition="not 'id' in request.matchdict">
$('#invoice_no').select2({
ajax: {
url: '/bjbqris/kodebayar/act',
dataType: 'json',
type: "GET",
quietMillis: 50,
data: function (q) {
return {
'term': q.term
};
},
processResults: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.nama+' - '+item.kode,
id: item.kode
}
})
};
}
}
});
$('#invoice_no').on("select2:select", function(e) {
$.ajax({
type: 'GET',
url: '/bjbqris/detail/act',
dataType: 'json',
data : {
term : $('#invoice_no').val()
},
success: function(data) {
$('#description').val(data.description);
$('#customer_name').val(data.customer_name);
$('#customer_phone').val(data.customer_phone);
$('#customer_email').val(data.customer_email);
$('#expired_date').val(data.expired_date);
$('#amount').val(data.amount);
}
});
});
</tal:block>
<tal:block tal:condition="'id' in request.matchdict and request.matchdict['id']">
$('#va_number').prop('readonly', true);
$('#invoice_no').prop('readonly', true);
$('#status').prop('readonly', true);
$('#billing_type').prop('readonly', true);
$('#va_type').prop('readonly', true);
$('#currency').prop('readonly', true);
$('#customer_id').prop('readonly', true);
$('#cin').prop('readonly', true);
$('#response_code').prop('readonly', true);
$('#response_message').prop('readonly', true);
</tal:block>
});
</script>
</div> <!-- /metal:content -->
</html>
\ No newline at end of file
<html metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Warning</h3>
</div>
<div class="panel-body">
CANCEL No. VA #${row.va_number}?
</div>
</div>
<div tal:content="structure form"/>
</div>
</html>
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<link href="/static/datatables/media/css/dataTables.bootstrap.css" rel="stylesheet">
<h4>Daftar BJB QRIS</h4>
<form id="filter_form" method="POST" enctype="multipart/form-data" accept-charset="utf-8" class="form-inline">
<div class="form-group">
<label for="exampleInputName2">Tahun</label>
<input class="form-control" id="tahun" name="tahun" type="text" value="${request.session['tahun']}"/>
</div>
</form>
<div class="clearfix" style="margin-top:20px"></div>
<div class="clearfix"></div>
<table id="table1" class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>ID</th>
<th>ID BILLING</th>
<th>Kode Bayar</th>
<th>Deskripsi</th>
<th>Subjek Nama</th>
<th>Jumlah</th>
<th>Refnum</th>
<th>Expired Date</th>
<th>Tgl Bayar</th>
<th>Status</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="form_cetak" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="cuDialogLabel">Cetak Daftar Penerimaan Harian</h3>
</div>
<div class="modal-body form-group">
<div class="input-group col-md-12">
<label class="control-label col-md-3">Pejabat</label>
<div class="col-md-7">
<input class="form-control" id="pejabat" type="text" >
<input type="hidden" class="form-control" name="id_pejabat" id="id_pejabat" >
</div>
</div>
<div class="clearfix" style="margin-top:20px"></div>
<div class="clearfix"></div>
</div>
<div class="modal-footer">
<div class="btn-group center-block" role="group">
<button class="btn btn-primary" id="btn_pdf">Cetak</button>
</div>
<button class="btn" data-dismiss="modal" aria-hidden="true" id="batal">Batal</button>
</div>
</div>
</div>
</div>
<script src="/static/datatables/media/js/jquery.dataTables.min.js"></script>
<script src="/static/datatables/media/js/dataTables.bootstrap.js"></script>
<script>
var mID;
var oTable;
var oTableUri = "/bjbqris"
var oTableUrl = oTableUri+"/grid/act";
$(document).ready(function () {
oTable = $('#table1').DataTable({
ajaxSource : oTableUrl,
//"bStateSave" : true,
serverSide : true,
"bProcessing" : true,
"sDom" : '<"toolbar">lfrtip',
"bScrollCollapse": true,
"bSort" : true,
"bSearch" : true,
"bInfo" : false,
"bFilter" : true,
"bAutoWidth" : false,
"bPaginate" : true,
"sPaginationType": "full_numbers",
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columnDefs: [{
searchable: false,
visible: false,
targets: [0]
}],
"language": {
"search" : "Cari: ",
"paginate":{
"first" : "Pertama ",
"last" : "Akhir ",
"previous": false,
"next" : false,
},
"lengthMenu": " _MENU_ baris "
},
});
var tb_array = [
'<div class="btn-group pull-left">',
' <button id="btn_add" class="btn btn btn-success" type="button">Create QRIS</button>',
//' <button id="btn_edit" class="btn btn btn-warning" type="button">Update VA</button>',
//' <button id="btn_update" class="btn btn btn-primary" type="button">Inquiry VA</button>',
//' <button id="btn_delete" class="btn btn btn-danger" type="button">Cancel VA</button>',
' <button id="btn_qrcode" class="btn btn btn-info" type="button">View QRCODE</button>',
' &nbsp;',
'</div>',
];
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$('#table1 tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
var aData = oTable.row( this ).data();
oTable.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
mID = aData[0];
oTable.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
});
$('#btn_add').click(function () {
window.location = oTableUri+'/add';
});
$("#btn_close").click(function () {
window.location = '/';
return false;
});
$("#btn_qrcode").click(function () {
if (mID) window.open(oTableUri+"/qrcode/act?id="+mID,"_blank","width=350,height=350");
else
alert("Pilih Baris yang akan di lihat...");
});
});
</script>
</div> <!-- metal:content -->
</html>
\ No newline at end of file
<img src="data:image/png;base64, ${qr}" alt="" width="300px" height="300px">
\ No newline at end of file
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<div class="panel panel-default">
<div class="panel-body">
<form id="cariform" method="POST" enctype="multipart/form-data" accept-charset="utf-8" class="form-horizontal">
<div class="alert alert-danger" tal:condition="form and form.error and True or False">
<div class="error-msg-lbl">Kesalahan Pengisian Form</div>
<p class="error-msg">${form.errormsg}</p>
</div>
<div class="form-group" tal:repeat="f form">
<div id="item-${f.oid}" style="${f.widget.hidden and 'display:none;' or 'display:block;'}">
<label for="${f.oid}" class="control-label col-md-2 ${f.required and 'required' or ''} " id="req-${f.oid}">
${f.title}</label>
<div class="col-md-3">
${structure:f.serialize()}
<p id="error-${f.oid}" class="help-block" tal:condition="f.error"
tal:repeat="error f.error.messages()">
${error}</p>
</div>
</div>
</div>
<div class="col-md-4">
<label class="control-label col-md-3"></label>
<button type="submit" class="btn btn-primary" id="simpan" name="simpan">Simpan</button>
<button type="submit" class="btn btn-warning" id="batal" name="batal">Tutup</button>
</div>
</form>
</div> <!--panel-body-->
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.4.4/js/bootstrap-datetimepicker.min.js" integrity="sha512-4lTnmq2kNbykTiOPulgEvxRgqegB5/YMhMqaBWvxji/9wRgR9W/TSGF51/mIG1hQ6janxTojpr41y5/gaW9LRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/smalot-bootstrap-datetimepicker/2.4.4/css/bootstrap-datetimepicker.min.css" integrity="sha512-m9g5oqvMhf2FsilNZqftBnOR1GW+dJpb1a8RN+R3Aw1dVI2AeDfpSOa9Sm48xMacONC1vJlM2iIadPy4uLEC4Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function () {
function formatNumber(toFormat) {
return toFormat.toString().replace(
/\B(?=(\d{3})+(?!\d))/g, "."
);
};
$('.input-date').datetimepicker({
format: "yyyy-mm-dd hh:ii:ss"
});
<tal:block tal:condition="not 'id' in request.matchdict">
$('#invoice_no').select2({
ajax: {
url: '/bjbva/kodebayar/act',
dataType: 'json',
type: "GET",
quietMillis: 50,
data: function (q) {
return {
'term': q.term
};
},
processResults: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.nama+' - '+item.kode,
id: item.kode
}
})
};
}
}
});
$('#invoice_no').on("select2:select", function(e) {
$.ajax({
type: 'GET',
url: '/bjbva/detail/act',
dataType: 'json',
data : {
term : $('#invoice_no').val()
},
success: function(data) {
$('#description').val(data.description);
$('#customer_name').val(data.customer_name);
$('#customer_phone').val(data.customer_phone);
$('#customer_email').val(data.customer_email);
$('#expired_date').val(data.expired_date);
$('#amount').val(data.amount);
}
});
});
</tal:block>
<tal:block tal:condition="'id' in request.matchdict and request.matchdict['id']">
$('#va_number').prop('readonly', true);
$('#invoice_no').prop('readonly', true);
$('#status').prop('readonly', true);
$('#billing_type').prop('readonly', true);
$('#va_type').prop('readonly', true);
$('#currency').prop('readonly', true);
$('#customer_id').prop('readonly', true);
$('#cin').prop('readonly', true);
$('#response_code').prop('readonly', true);
$('#response_message').prop('readonly', true);
</tal:block>
});
</script>
</div> <!-- /metal:script -->
</html>
\ No newline at end of file
<html metal:use-macro="load: ../main.pt">
<div metal:fill-slot="content">
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Warning</h3>
</div>
<div class="panel-body">
CANCEL No. VA #${row.va_number}?
</div>
</div>
<div tal:content="structure form"/>
</div>
</html>
<html metal:use-macro="load: ../base.pt">
<div metal:fill-slot="content">
<link href="/static/datatables/media/css/dataTables.bootstrap.css" rel="stylesheet">
<h4>Daftar BJB VA</h4>
<div class="dataTables_wrapper form-inline no-footer">
<form id="filter_form" method="POST" enctype="multipart/form-data" accept-charset="utf-8" class="form-inline">
<div class="form-group">
<label for="exampleInputName2">Tahun</label>
<input class="form-control" id="tahun" name="tahun" type="text" value="${request.session['tahun']}"/>
</div>
</form>
<div class="clearfix" style="margin-top:20px"></div>
<div class="clearfix"></div>
<table id="table1" class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>ID</th>
<th>No. VA</th>
<th>Kode Bayar</th>
<th>Deskripsi</th>
<th>Subjek Nama</th>
<th>Jumlah</th>
<th>Refnum</th>
<th>Expired Date</th>
<th>Tgl Bayar</th>
<th>Status</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div id="form_cetak" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="cuDialogLabel">Cetak Daftar Penerimaan Harian</h3>
</div>
<div class="modal-body form-group">
<div class="input-group col-md-12">
<label class="control-label col-md-3">Pejabat</label>
<div class="col-md-7">
<input class="form-control" id="pejabat" type="text" >
<input type="hidden" class="form-control" name="id_pejabat" id="id_pejabat" >
</div>
</div>
<div class="clearfix" style="margin-top:20px"></div>
<div class="clearfix"></div>
</div>
<div class="modal-footer">
<div class="btn-group center-block" role="group">
<button class="btn btn-primary" id="btn_pdf">Cetak</button>
</div>
<button class="btn" data-dismiss="modal" aria-hidden="true" id="batal">Batal</button>
</div>
</div>
</div>
</div>
<script src="/static/datatables/media/js/jquery.dataTables.min.js"></script>
<script src="/static/datatables/media/js/dataTables.bootstrap.js"></script>
<script>
var mID;
var oTable;
var oTableUri = "/bjbva"
var oTableUrl = oTableUri+"/grid/act";
$(document).ready(function () {
oTable = $('#table1').DataTable({
ajaxSource : oTableUrl,
//"bStateSave" : true,
serverSide : true,
"bProcessing" : true,
"sDom" : '<"toolbar">lfrtip',
"bScrollCollapse": true,
"bSort" : true,
"bSearch" : true,
"bInfo" : false,
"bFilter" : true,
"bAutoWidth" : false,
"bPaginate" : true,
"sPaginationType": "full_numbers",
lengthMenu: [
[10, 25, 50, 100],
[10, 25, 50, 100]
],
columnDefs: [{
searchable: false,
visible: false,
targets: [0]
}],
"language": {
"search" : "Cari: ",
"paginate":{
"first" : "Pertama ",
"last" : "Akhir ",
"previous": false,
"next" : false,
},
"lengthMenu": " _MENU_ baris "
},
});
var tb_array = [
'<div class="btn-group pull-left">',
' <button id="btn_add" class="btn btn btn-success" type="button">Create VA</button>',
' <button id="btn_edit" class="btn btn btn-warning" type="button">Update VA</button>',
' <button id="btn_update" class="btn btn btn-primary" type="button">Inquiry VA</button>',
' <button id="btn_delete" class="btn btn btn-danger" type="button">Cancel VA</button>',
' &nbsp;',
'</div>',
];
var tb = tb_array.join(' ');
$("div.toolbar").html(tb);
$("div.toolbar").attr('style', 'display:block; float: left; margin-bottom:6px; line-height:16px;');
$('#table1 tbody').on('click', 'tr', function () {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
} else {
var aData = oTable.row( this ).data();
oTable.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
mID = aData[0];
oTable.$('tr.row_selected').removeClass('row_selected');
$(this).addClass('row_selected');
}
});
$('#btn_add').click(function () {
window.location = oTableUri+'/add';
});
$('#btn_edit').click(function () {
if (mID) window.location = oTableUri+'/'+mID+'/edt';
else
alert("Pilih Baris yang akan di edit...");
});
$('#btn_delete').click(function () {
if (mID) window.location = oTableUri+'/'+mID+'/del';
else
alert("Pilih Baris yang akan di hapus...");
});
$('#btn_update').click(function () {
if (mID) {
$.ajax({
type: 'GET',
url: oTableUri+'/update/act',
dataType: 'json',
data : {
term : mID
},
success: function(data) {
oTable.ajax.url(oTableUrl).load();
}
});
}
else
alert("Pilih Baris yang akan di inquiry...");
});
$("#btn_close").click(function () {
window.location = '/';
return false;
});
});
</script>
</div>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!