Commit 9260c86c by Owo Sugiana

Tambah tangerang_kabupaten

1 parent 76a4efa9
dist
build
*egg-info
test-*
0.2 2020-05-09
--------------
- Konfigurasi kini memuat nama modul
- Tambah modul tangerang_kabupaten
0.1.3 2020-01-14
----------------
- get_last_payment() memperhatikan status pembayaran.
......
Struktur Tabel BPHTB
====================
BPHTB adalah Bea Peralihan Hak atas Tanah dan Bangunan.
BPHTB adalah Bea Perolehan Hak atas Tanah dan Bangunan.
Paket ini selain berisi struktur tabel juga memuat query yang kerap digunakan
untuk proses:
1. inquiry (cek tagihan)
2. payment (pembayaran)
3. reversal (pembatalan pembayaran)
1. Inquiry (cek tagihan)
2. Payment (pembayaran)
3. Reversal (pembatalan pembayaran)
Uji Coba
--------
......@@ -16,12 +16,13 @@ Uji Coba
Buat file ``test-cilegon.ini`` seperti contoh berikut ini::
[main]
db_url = postgresql://sugiana:a@localhost/bphtb_cilegon
module = cilegon
db_url = postgresql://user:pass@localhost/db
persen_denda = 2
Sesuaikanlah pada ``db_url``. Kemudian dapatkan daftar tagihan::
$ env/bin/bphtb_cilegon_available_invoice test-cilegon.ini
$ ~/env/bin/bphtb_available_invoice test-cilegon.ini
Nanti akan tampil seperti ini::
......@@ -32,14 +33,14 @@ Nanti akan tampil seperti ini::
Kolom kedua adalah Invoice ID atau sering disebut sebagai nomor bayar. Nomor
ini bekal untuk inquiry atau cek tagihan::
$ env/bin/bphtb_cilegon_inquiry test-cilegon.ini --invoice-id=10241
$ ~/env/bin/bphtb_inquiry test-cilegon.ini --invoice-id=10241
Untuk melanjutkan pembayaran tambahkan opsi ``--payment``::
$ env/bin/bphtb_cilegon_inquiry test-cilegon.ini --invoice-id=10241 --payment
$ ~/env/bin/bphtb_inquiry test-cilegon.ini --invoice-id=10241 --payment
Sedangkan untuk membatalkannya tambahkan opsi ``--reversal``::
$ env/bin/bphtb_cilegon_inquiry test-cilegon.ini --invoice-id=10241 --reversal
$ ~/env/bin/bphtb_inquiry test-cilegon.ini --invoice-id=10241 --reversal
Selamat mencoba, semoga berhasil.
[main]
module = tangerang_kabupaten
db_url = postgresql://username:password@localhost/database
persen_denda = 2
from datetime import date
from sqlalchemy import func
from sqlalchemy.orm import sessionmaker
from opensipkd.bphtb.cilegon.models import (
from sqlalchemy import (
func,
or_,
)
from opensipkd.hitung import (
hitung_denda,
round_up,
)
from opensipkd.string.money import thousand
from ..services import AvailableInvoice as BaseAvailableInvoice
from .models import (
Spt,
DetailSpt,
Pembayaran,
......@@ -9,15 +17,23 @@ from opensipkd.bphtb.cilegon.models import (
Notaris,
User,
)
from opensipkd.hitung import hitung_denda
DBSession = None # override, please
def get_db_session():
return DBSession
class Inquiry:
def __init__(self, invoice_id, persen_denda=2):
def __init__(self, invoice_id, persen_denda=2, tgl_bayar=None):
self.invoice_id = invoice_id
self.persen_denda = persen_denda
if tgl_bayar:
self.tgl_bayar = tgl_bayar
else:
self.tgl_bayar = date.today()
q = DBSession.query(Pembayaran).filter_by(
t_kodebayarbanksppt=invoice_id).order_by(
Pembayaran.t_idpembayaranspt)
......@@ -34,22 +50,32 @@ class Inquiry:
self.pemeriksaan = q.first()
self.profile = self.get_profile()
self.notaris = self.get_notaris()
self.hitung()
def hitung(self):
self.total_bayar = self.get_payment_amount()
self.total = self.tagihan = self.denda = self.bln_tunggakan = \
self.discount = 0
if self.payment.t_statusbayarspt:
self.tagihan = self.denda = self.total = 0
return
self.tagihan = self.invoice.t_totalspt
self.total = self.tagihan - self.total_bayar
if self.total <= 0:
self.total = 0
self.denda = 0
return
if not self.invoice.t_tgljatuhtempospt:
self.denda = 0
return
self.denda = hitung_denda(
self.tagihan, self.invoice.t_tgljatuhtempospt, persen_denda)
self.total = self.total - self.denda
self.hitung_denda()
self.hitung_discount()
self.total = self.total + self.denda - self.discount
def hitung_denda(self):
if self.invoice.t_tgljatuhtempospt:
self.bln_tunggakan, denda = hitung_denda(
self.tagihan, self.invoice.t_tgljatuhtempospt,
self.persen_denda, self.tgl_bayar)
self.denda = round_up(denda)
def hitung_discount(self):
self.discount = 0
def get_profile(self):
q = DBSession.query(DetailSpt).filter_by(t_idspt=self.invoice.t_idspt)
......@@ -110,6 +136,9 @@ class Inquiry:
def get_alamat_op(self):
return self.profile.t_alamatop
def get_kota_wp(self):
pass
def get_kota_op(self):
return self.profile.t_kabupatenop
......@@ -145,11 +174,10 @@ class Inquiry:
return row.jml or 0
def do_payment(self, ntb):
self.payment.t_tanggalpembayaran = date.today()
self.payment.t_tanggalpembayaran = self.tgl_bayar
self.payment.t_nilaipembayaranspt = self.total
self.payment.t_statusbayarspt = True
DBSession.add(self.payment)
DBSession.flush()
return self.payment
......@@ -171,4 +199,41 @@ class Reversal:
self.payment.t_nilaipembayaranspt = 0
self.payment.t_statusbayarspt = False
DBSession.add(self.payment)
DBSession.flush()
class AvailableInvoice(BaseAvailableInvoice):
def get_query(self):
q = DBSession.query(
Pembayaran.t_kodebayarbanksppt, Spt.t_tgljatuhtempospt).\
filter(
Pembayaran.t_idspt==Spt.t_idspt,
or_(Pembayaran.t_statusbayarspt==None,
Pembayaran.t_statusbayarspt==False))
if self.option.tahun:
q = q.filter(Spt.t_periodespt==self.option.tahun)
if self.option.belum_jatuh_tempo or self.option.lewat_jatuh_tempo:
q = q.filter(Spt.t_tgljatuhtempospt != None)
kini = date.today()
if self.option.belum_jatuh_tempo:
q = q.filter(Spt.t_tgljatuhtempospt >= kini)
else:
q = q.filter(Spt.t_tgljatuhtempospt < kini)
print('jatuh tempo')
return q.order_by(Pembayaran.t_idpembayaranspt.desc())
def get_message(self, row):
inq = Inquiry(row.t_kodebayarbanksppt, self.persen_denda)
if not inq.total:
return
msg = '{} {} {} {}'.format(
inq.invoice_id, inq.get_tahun(), inq.get_nop(),
inq.get_nama())
if inq.total_bayar:
msg = '{} Rp {} - Rp {} = Rp {}'.format(
msg, thousand(inq.tagihan), thousand(inq.total_bayar),
thousand(inq.total))
else:
msg = '{} Rp {}'.format(msg, thousand(inq.total))
if row.t_tgljatuhtempospt:
return '{} jatuh tempo {}'.format(msg, row.t_tgl_jatuhtempospt)
return msg
import sys
from configparser import ConfigParser
from argparse import ArgumentParser
from optparse import OptionParser
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
def get_option(argv):
default_count = 10
help_count = 'default {}'.format(default_count)
pars = ArgumentParser()
pars.add_argument('conf')
pars.add_argument('--tahun', type=int)
pars.add_argument('--belum-jatuh-tempo', action='store_true')
pars.add_argument('--lewat-jatuh-tempo', action='store_true')
pars.add_argument(
'--count', type=int, default=default_count, help=help_count)
return pars.parse_args(argv)
def main(argv=sys.argv):
option = get_option(argv[1:])
conf = ConfigParser()
conf.read(option.conf)
module_name = conf.get('main', 'module')
module = __import__('opensipkd.bphtb.' + module_name + '.services')
area_module = getattr(module.bphtb, module_name)
services_module = getattr(area_module, 'services')
AvailableInvoice = services_module.AvailableInvoice
db_url = conf.get('main', 'db_url')
persen_denda = conf.getfloat('main', 'persen_denda')
engine = create_engine(db_url)
session_factory = sessionmaker(bind=engine)
services_module.DBSession = session_factory()
a = AvailableInvoice(persen_denda, option)
a.show()
import sys
from datetime import datetime
from configparser import ConfigParser
from optparse import OptionParser
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import transaction
from zope.sqlalchemy import register
from opensipkd.string.money import thousand
def show_val(label, value):
print('{}: {}'.format(label, value))
def show_rp(label, value):
show_val(label, 'Rp {}'.format(thousand(value)))
def get_option(argv):
pars = OptionParser()
pars.add_option('-i', '--invoice-id')
pars.add_option('', '--payment', action='store_true')
pars.add_option('', '--reversal', action='store_true')
return pars.parse_args(argv)
def show(inq):
show_val('Invoice ID', inq.invoice_id)
show_val('Luas Tanah', inq.get_luas_tanah())
show_val('Luas Bangunan', inq.get_luas_bangunan())
show_rp('NPOP', inq.get_npop())
show_val('Jenis Perolehan Hak', inq.get_jenis_perolehan_hak())
show_val('Alamat Objek Pajak', inq.get_alamat_op())
show_val('Kelurahan Objek Pajak', inq.get_kelurahan_op())
show_val('Kecamatan Objek Pajak', inq.get_kecamatan_op())
show_val('Kota Objek Pajak', inq.get_kota_op())
show_val('NOP', inq.get_nop())
show_rp('Tagihan', inq.tagihan)
show_rp('Denda', inq.denda)
show_rp('Discount', inq.discount)
show_rp('Total Bayar', inq.total_bayar)
show_rp('Total Tagihan', inq.total)
show_val('Nama Notaris', inq.get_nama_notaris())
show_val('Nama Wajib Pajak', inq.get_nama())
show_val('NPWP', inq.get_npwp())
show_val('Alamat Wajib Pajak', inq.get_alamat_wp())
show_val('Kelurahan Wajib Pajak', inq.get_kelurahan_wp())
show_val('Kecamatan Wajib Pajak', inq.get_kecamatan_wp())
show_val('RT Wajib Pajak', inq.get_rt_wp())
show_val('RW Wajib Pajak', inq.get_rw_wp())
show_val('Kode Pos Wajib Pajak', inq.get_kode_pos_wp())
show_val('Kota Wajib Pajak', inq.get_kota_wp())
show_val('Tahun Pajak', inq.get_tahun())
show_val('Is Available', inq.is_available())
def show_pkey_values(row):
print('Primary key tabel {}:'.format(row.__table__.name))
for c in row.__table__.columns:
if c.primary_key:
val = getattr(row, c.name)
show_val(' '+c.name, val)
def main(argv=sys.argv):
option, remain = get_option(argv[1:])
conf_file = remain[0]
invoice_id = option.invoice_id
conf = ConfigParser()
conf.read(conf_file)
db_url = conf.get('main', 'db_url')
engine = create_engine(db_url)
module_name = conf.get('main', 'module')
module = __import__('opensipkd.bphtb.' + module_name + '.services')
area_module = getattr(module.bphtb, module_name)
services_module = getattr(area_module, 'services')
AvailableInvoice = services_module.AvailableInvoice
session_factory = sessionmaker(bind=engine)
services_module.DBSession = session_factory()
register(services_module.DBSession)
inq = services_module.Inquiry(
invoice_id, conf.getfloat('main', 'persen_denda'))
if not inq.invoice:
print('Invoice ID {} tidak ada.'.format(invoice_id))
return
show(inq)
if option.payment:
if not inq.total:
print('Tidak ada tagihan, tidak ada yang perlu dibayar.')
return
ntb = datetime.now().strftime('%y%m%d%H%M%S')
with transaction.manager:
pay = inq.do_payment(ntb)
show_pkey_values(pay)
print('Berhasil dibayar')
if option.reversal:
rev = services_module.Reversal(invoice_id)
pay = rev.payment
if not pay:
print('Pembayaran tidak ditemukan, tidak ada yang perlu dibatalkan.')
return
with transaction.manager:
rev.do_reversal()
show_pkey_values(pay)
print('Berhasil dibatalkan')
from time import time
class AvailableInvoice:
def __init__(self, persen_denda=2, option=None):
self.option = option
self.count = option and option.count or 10
self.persen_denda = persen_denda
def show(self):
offset = -1
count = 0
max_count_length = len(str(self.count))
q = self.get_query()
awal = time()
while True:
if time() - awal > 10:
break
offset += 1
row = q.offset(offset).first()
if not row:
break
msg = self.get_message(row)
if not msg:
continue
count += 1
no = str(count).zfill(max_count_length)
msg = '#{}/{} {}'.format(no, self.count, msg)
print(msg)
if count == self.count:
break
def get_query(self):
pass
def get_message(self, row):
pass
# Nomor Objek Pajak
NOP = [
('Propinsi', 2, 'N'),
('Kabupaten', 2, 'N'),
('Kecamatan', 3, 'N'),
('Kelurahan', 3, 'N'),
('Blok', 3, 'N'),
('Urut', 4, 'N'),
('Jenis', 1, 'N'),
]
INVOICE_ID = [
['Tahun', 4, 'N'],
['Kode', 2, 'N'],
['SSPD No', 6, 'N'],
]
INVOICE_ID_LENGTH = 0
for nama, size, tipe in INVOICE_ID:
INVOICE_ID_LENGTH += size
INVOICE_ID_V2 = [
['Provinsi', 2, 'N'],
['Kabupaten', 2, 'N'],
['Jenis Pajak', 2, 'N'],
['Tahun', 2, 'N'],
['Kode', 2, 'N'],
['SSPD No', 6, 'N'],
]
INVOICE_ID_LENGTH_V2 = 0
for nama, size, tipe in INVOICE_ID_V2:
INVOICE_ID_LENGTH_V2 += size
......@@ -33,8 +33,8 @@ setuptools.setup(
],
entry_points={
'console_scripts': [
'bphtb_cilegon_available_invoice = opensipkd.bphtb.cilegon.scripts.available_invoice:main',
'bphtb_cilegon_inquiry = opensipkd.bphtb.cilegon.scripts.inquiry:main',
'bphtb_available_invoice = opensipkd.bphtb.scripts.available_invoice:main',
'bphtb_inquiry = opensipkd.bphtb.scripts.inquiry:main',
]
},
)
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!