Commit 4f7c810c by Owo Sugiana

Penambahan rumus Kota Bogor

1 parent 07b75e49
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
dist dist
__pycache__ __pycache__
*.pyc *.pyc
test.ini
0.1.2 2020-04-19
----------------
- Tambah pengurangan pokok untuk Kota Bogor.
0.1.1 2019-05-27 0.1.1 2019-05-27
---------------- ----------------
- Tambah default model siap pakai. - Tambah default model siap pakai.
......
...@@ -3,3 +3,47 @@ SISMIOP a.k.a PBB ...@@ -3,3 +3,47 @@ SISMIOP a.k.a PBB
Struktur tabel SISMIOP yang merupakan sistem PBB (Pajak Bumi dan Bangunan). Struktur tabel SISMIOP yang merupakan sistem PBB (Pajak Bumi dan Bangunan).
Biasanya dari Oracle. Biasanya dari Oracle.
Pemasangan
----------
Buat Python virtual environment::
$ python3 -m venv ~/env
Setelah paket ini diunduh selanjutnya dipasang::
$ ~/env/bin/pip install -e sismiop-models
Salin konfigurasi::
$ cd sismiop-models
$ cp development.ini test.ini
Sesuaikan isinya terutama pada ``module`` dan ``db_url``.
Untuk mendapatkan daftar tagihan yang belum dibayar::
$ ~/env/bin/pbb_available_invoice test.ini
Jika ingin tahun tertentu gunakan opsi ``--tahun``::
$ ~/env/bin/pbb_available_invoice test.ini --tahun=2020
Lihat opsi lainnya dengan ``--help``::
$ ~/env/bin/pbb_available_invoice test.ini --help
Untuk melihat rincian tagihan::
$ ~/env/bin/pbb_inquiry test.ini -i 3271010001001000402019
Coba pembayaran::
$ ~/env/bin/pbb_inquiry test.ini -i 3271010001001000402019 --payment
Batalkan::
$ ~/env/bin/pbb_inquiry test.ini -i 3271010001001000402019 --reversal
Selamat mencoba.
[main]
# Daftar modul ada di direktori sismiop/services. Yang tersedia adalah
# default dan bogor_kota.
module = default
db_url = postgresql://username:password@localhost/db_name
persen_denda = 2
# Digunakan saat payment
nip_pencatat = 999999999
kd_kanwil = 01
kd_kantor = 01
kd_tp = 71
...@@ -13,6 +13,10 @@ version = line.split()[0] ...@@ -13,6 +13,10 @@ version = line.split()[0]
requires = [ requires = [
'sqlalchemy', 'sqlalchemy',
'transaction',
'zope.sqlalchemy',
'psycopg2-binary',
'opensipkd-hitung @ git+https://git.opensipkd.com/sugiana/opensipkd-hitung',
] ]
...@@ -26,15 +30,15 @@ setup( ...@@ -26,15 +30,15 @@ setup(
license='PostgreSQL License', license='PostgreSQL License',
packages=[ packages=[
'sismiop.models', 'sismiop.models',
'sismiop.models.default',
'sismiop.services', 'sismiop.services',
'sismiop.services.default',
'sismiop.scripts'], 'sismiop.scripts'],
install_requires=requires, install_requires=requires,
zip_safe=False, zip_safe=False,
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'pbb_init_db = sismiop.scripts.init_db:main',
'pbb_available_invoice = sismiop.scripts.available_invoice:main', 'pbb_available_invoice = sismiop.scripts.available_invoice:main',
'pbb_inquiry = sismiop.scripts.inquiry:main',
] ]
} }
) )
from sqlalchemy import (
Column,
Integer,
String,
Float,
)
from sqlalchemy.ext.declarative import declarative_base
from .objek_pajak import ObjekPajakMixin
from .sppt import SpptMixin
from .pembayaran_sppt import PembayaranSpptMixin
from .kelurahan import KelurahanMixin
from .kecamatan import KecamatanMixin
from .propinsi import PropinsiMixin
Base = declarative_base()
class ObjekPajak(Base, ObjekPajakMixin):
pass
class Sppt(Base, SpptMixin):
pass
class PembayaranSppt(Base, PembayaranSpptMixin):
pass
class Kelurahan(Base, KelurahanMixin):
pass
class Kecamatan(Base, KecamatanMixin):
pass
class Propinsi(Base, PropinsiMixin):
pass
class PenguranganCovid(Base):
__tablename__ = 'pengurangan_covid'
id = Column(Integer, primary_key=True)
kd_propinsi = Column(String(2), nullable=False)
kd_dati2 = Column(String(2), nullable=False)
kd_kecamatan = Column(String(3), nullable=False)
kd_kelurahan = Column(String(3), nullable=False)
kd_blok = Column(String(3), nullable=False)
no_urut = Column(String(4), nullable=False)
kd_jns_op = Column(String(1), nullable=False)
thn_pajak_sppt = Column(String(4), nullable=False)
pembayaran_sppt_ke = Column(Integer, nullable=False)
pokok = Column(Float, nullable=False)
denda = Column(Float, nullable=False)
#__table_args__ = (
# ForeignKeyConstraint(
# [kd_propinsi, kd_dati2, kd_kecamatan, kd_kelurahan, kd_blok,
# no_urut, kd_jns_op, thn_pajak_sppt, pembayaran_sppt_ke],
# [PembayaranSppt.kd_propinsi, PembayaranSppt.kd_dati2,
# PembayaranSppt.kd_kecamatan, PembayaranSppt.kd_kelurahan,
# PembayaranSppt.kd_blok, PembayaranSppt.no_urut,
# PembayaranSppt.kd_jns_op, PembayaranSppt.thn_pajak_sppt,
# PembayaranSppt.pembayaran_sppt_ke]),
# )
class PenguranganPst(Base):
__tablename__ = 'pengurangan_pst'
id = Column(Integer, primary_key=True)
kd_kanwil = Column(String(2), nullable=False)
kd_kantor = Column(String(2), nullable=False)
thn_pelayanan = Column(String(4), nullable=False)
no_urut_pelayanan = Column(String(3), nullable=False)
kd_propinsi_pemohon = Column(String(2), nullable=False)
kd_dati2_pemohon = Column(String(2), nullable=False)
kd_kecamatan_pemohon = Column(String(3), nullable=False)
kd_kelurahan_pemohon = Column(String(3), nullable=False)
kd_blok_pemohon = Column(String(3), nullable=False)
no_urut_pemohon = Column(String(4), nullable=False)
kd_jns_op_pemohon = Column(String(1), nullable=False)
thn_peng_pst = Column(String(4), nullable=False)
jns_sk = Column(String(1), nullable=False)
no_sk = Column(String(30), nullable=False)
status_sk_peng_pst = Column(Integer, nullable=False)
pct_pengurangan_pst = Column(String(1), nullable=False)
from sqlalchemy.ext.declarative import declarative_base
from ..sppt import SpptMixin
from ..pembayaran_sppt import PembayaranSpptMixin
from ..kelurahan import KelurahanMixin
from ..kecamatan import KecamatanMixin
from ..propinsi import PropinsiMixin
Base = declarative_base()
class Sppt(Base, SpptMixin):
pass
class PembayaranSppt(Base, PembayaranSpptMixin):
pass
class Kelurahan(Base, KelurahanMixin):
pass
class Kecamatan(Base, KecamatanMixin):
pass
class Propinsi(Base, PropinsiMixin):
pass
import sys import sys
from configparser import ConfigParser from configparser import ConfigParser
from optparse import OptionParser
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
import sismiop.services import sismiop.services.base
from sismiop.services.default import AvailableInvoice
def get_option(argv):
default_count = 10
help_count = 'default {}'.format(default_count)
pars = OptionParser()
pars.add_option('', '--tahun')
pars.add_option(
'', '--count', type=int, default=default_count, help=help_count)
return pars.parse_args(argv)
def main(argv=sys.argv): def main(argv=sys.argv):
conf_file = argv[1] option, remain = get_option(argv[1:])
count = int(option.count)
conf_file = remain[0]
conf = ConfigParser() conf = ConfigParser()
conf.read(conf_file) conf.read(conf_file)
module_name = conf.get('main', 'module')
module = __import__('sismiop.services.' + module_name)
sub_module = getattr(module.services, module_name)
AvailableInvoice = sub_module.AvailableInvoice
db_url = conf.get('main', 'db_url') db_url = conf.get('main', 'db_url')
persen_denda = conf.getfloat('main', 'persen_denda') persen_denda = conf.getfloat('main', 'persen_denda')
engine = create_engine(db_url) engine = create_engine(db_url)
session_factory = sessionmaker(bind=engine) session_factory = sessionmaker(bind=engine)
sismiop.services.DBSession = session_factory() sismiop.services.base.DBSession = session_factory()
a = AvailableInvoice(persen_denda) a = AvailableInvoice(persen_denda, count, option.tahun)
a.show() a.show()
import sys
from configparser import ConfigParser
from sqlalchemy import create_engine
from sismiop.models.default import Base
def main(argv=sys.argv):
config_uri = argv[1]
conf = ConfigParser()
conf.read(config_uri)
db_url = conf.get('main', 'db_url')
engine = create_engine(db_url)
Base.metadata.create_all(engine)
import sys
import locale
from datetime import date
from configparser import ConfigParser
from optparse import OptionParser
import transaction
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import register
import sismiop.services.base
locale.setlocale(locale.LC_ALL, 'id_ID.utf8')
def thousand(n):
return locale.format('%.0f', n, True)
def show_val(label, value):
print('{}: {}'.format(label, value))
def show_rp(label, value):
show_val(label, 'Rp {}'.format(thousand(value)))
def date_from_str(s):
d, m, y = s.split('-')
return date(int(y), int(m), int(d))
def get_option(argv):
help_tgl = 'butuh --payment'
pars = OptionParser()
pars.add_option('-i', '--invoice-id')
pars.add_option('', '--payment', action='store_true')
pars.add_option('', '--tgl-bayar', help=help_tgl)
pars.add_option('', '--reversal', action='store_true')
return pars.parse_args(argv)
def show(inq):
show_val('Invoice ID', inq.invoice_id_raw)
show_val('Kelurahan Objek Pajak', inq.get_kelurahan_op())
show_val('Kecamatan Objek Pajak', inq.get_kecamatan_op())
show_val('Provinsi Objek Pajak', inq.get_propinsi_op())
show_val('Alamat Objek Pajak', inq.get_alamat_op())
show_val('Luas Tanah', inq.get_luas_tanah())
show_val('Luas Bangunan', inq.get_luas_bangunan())
show_rp('Tagihan', inq.tagihan)
show_rp('Denda', inq.denda)
show_rp('Total Bayar', inq.total_bayar)
show_rp('Total Tagihan', inq.total)
show_val('Jatuh Tempo', inq.get_jatuh_tempo())
show_val('Tahun Pajak', inq.get_tahun())
def main(argv=sys.argv):
option, remain = get_option(argv[1:])
invoice_id = option.invoice_id
if option.tgl_bayar:
tgl_bayar = date_from_str(option.tgl_bayar)
else:
tgl_bayar = None
conf_file = remain[0]
conf = ConfigParser()
conf.read(conf_file)
module_name = conf.get('main', 'module')
module = __import__('sismiop.services.' + module_name)
sub_module = getattr(module.services, module_name)
Inquiry = sub_module.Inquiry
Reversal = sub_module.Reversal
db_url = conf.get('main', 'db_url')
engine = create_engine(db_url)
session_factory = sessionmaker(bind=engine)
sismiop.services.base.DBSession = session_factory()
register(sismiop.services.base.DBSession)
with transaction.manager:
inq = 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 inq.is_paid():
print('Tidak ada tagihan, tidak ada yang perlu dibayar.')
return
if not inq.is_available():
print('Tagihan tidak diperkenankan dibayar melalui jalur ini.')
return
tp = dict(
kd_kanwil=conf.get('main', 'kd_kanwil'),
kd_kantor=conf.get('main', 'kd_kantor'),
kd_tp=conf.get('main', 'kd_tp'))
nip = conf.get('main', 'nip_pencatat')
pay = inq.do_payment(tp, nip, tgl_bayar)
print(
'Berhasil dibayar pada urutan ke-{}'.format(
pay.pembayaran_sppt_ke))
if option.reversal:
rev = Reversal(invoice_id)
pay = rev.payment
if not pay:
print('Pembayaran tidak ditemukan, tidak ada yang perlu dibatalkan.')
return
rev.do_reversal()
print(
'Pembayaran ke-{} berhasil dibatalkan'.format(
pay.pembayaran_sppt_ke))
DBSession = None
def get_db_session(db_session=None):
return db_session or DBSession
from time import time
from datetime import (
date,
datetime,
)
from sqlalchemy import func
import locale
from opensipkd.string import FixLength
from opensipkd.hitung import (
hitung_denda,
round_up,
)
# Ditetapkan dari luar
DBSession = None
locale.setlocale(locale.LC_ALL, 'id_ID.utf8')
INVOICE_ID = [
('Propinsi', 2, 'N'),
('Kabupaten', 2, 'N'),
('Kecamatan', 3, 'N'),
('Kelurahan', 3, 'N'),
('Blok', 3, 'N'),
('Urut', 4, 'N'),
('Jenis', 1, 'N'),
('Tahun', 4, 'N'),
]
def get_db_session():
return DBSession
def thousand(n):
return locale.format('%0.f', n, True)
def get_id(row):
return ''.join(
[row.kd_propinsi, row.kd_dati2, row.kd_kecamatan,
row.kd_kelurahan, row.kd_blok, row.no_urut, row.kd_jns_op,
row.thn_pajak_sppt])
class Query:
def __init__(self, invoice_id=None, invoice=None):
self.invoice_id = FixLength(INVOICE_ID)
if invoice:
self.invoice = invoice
self.invoice_id_raw = get_id(invoice)
self.invoice_id.set_raw(self.invoice_id_raw)
else:
self.invoice_id_raw = invoice_id
self.invoice_id.set_raw(invoice_id)
q = self.query_invoice()
self.invoice = q.first()
def get_op_model(self): # Objek Pajak
pass
def get_invoice_model(self):
pass
def get_payment_model(self):
pass
def get_filter_op(self, q):
inv_id = self.invoice_id
return q.filter_by(
kd_propinsi=inv_id['Propinsi'], kd_dati2=inv_id['Kabupaten'],
kd_kecamatan=inv_id['Kecamatan'],
kd_kelurahan=inv_id['Kelurahan'],
kd_blok=inv_id['Blok'], no_urut=inv_id['Urut'],
kd_jns_op=inv_id['Jenis'])
def get_filter(self, q):
inv_id = self.invoice_id
q = self.get_filter_op(q)
return q.filter_by(thn_pajak_sppt=inv_id['Tahun'])
def get_query(self, model):
q = DBSession.query(model)
return self.get_filter(q)
def query_op(self):
OP = self.get_op_model()
q = DBSession.query(OP)
return self.get_filter_op(q)
def query_invoice(self):
Invoice = self.get_invoice_model()
return self.get_query(Invoice)
def query_payment(self):
Payment = self.get_payment_model()
return self.get_query(Payment)
def invoice2payment(self):
Payment = self.get_payment_model()
q = self.query_payment()
q = q.order_by(Payment.pembayaran_sppt_ke.desc())
return q.first()
class Inquiry(Query):
def __init__(self, invoice_id=None, persen_denda=2, invoice=None):
Query.__init__(self, invoice_id, invoice)
self.persen_denda = persen_denda
if self.invoice:
self.hitung()
def get_kelurahan_model(self):
pass
def get_kecamatan_model(self):
pass
def get_propinsi_model(self):
pass
def get_kelurahan_op(self):
Kelurahan = self.get_kelurahan_model()
inv_id = self.invoice_id
q = DBSession.query(Kelurahan).filter_by(
kd_propinsi=inv_id['Propinsi'], kd_dati2=inv_id['Kabupaten'],
kd_kecamatan=inv_id['Kecamatan'],
kd_kelurahan=inv_id['Kelurahan'])
r = q.first()
return r and r.nm_kelurahan or ''
def get_kecamatan_op(self):
Kecamatan = self.get_kecamatan_model()
inv_id = self.invoice_id
q = DBSession.query(Kecamatan).filter_by(
kd_propinsi=inv_id['Propinsi'], kd_dati2=inv_id['Kabupaten'],
kd_kecamatan=inv_id['Kecamatan'])
r = q.first()
return r and r.nm_kecamatan or ''
def get_propinsi_op(self):
Propinsi = self.get_propinsi_model()
inv_id = self.invoice_id
q = DBSession.query(Propinsi).filter_by(kd_propinsi=inv_id['Propinsi'])
r = q.first()
return r and r.nm_propinsi or ''
def get_alamat_op(self):
q = self.query_op()
op = q.first()
if op:
return op.jalan_op
return self.invoice.jln_wp_sppt
def get_jatuh_tempo(self):
return self.invoice.tgl_jatuh_tempo_sppt
def get_tahun(self):
return self.invoice.thn_pajak_sppt
def get_luas_tanah(self):
return self.invoice.luas_bumi_sppt
def get_luas_bangunan(self):
return self.invoice.luas_bng_sppt
def is_paid(self):
return self.total < 1
def is_available(self):
return not self.is_paid() and \
self.invoice.status_pembayaran_sppt in ('0', '1')
def hitung_pokok(self):
Payment = self.get_payment_model()
q = DBSession.query(
func.sum(Payment.jml_sppt_yg_dibayar).
label('jml_sppt_yg_dibayar'),
func.sum(Payment.denda_sppt).
label('denda_sppt'))
q = self.get_filter(q)
bayar = q.first()
self.total_bayar = bayar.jml_sppt_yg_dibayar or 0
denda_lalu = bayar.denda_sppt or 0
sisa = float(self.total_bayar - denda_lalu)
tagihan = self.invoice.pbb_yg_harus_dibayar_sppt - sisa
self.tagihan = round_up(tagihan)
def hitung_denda(self, tgl_bayar):
bln_tunggakan, denda = hitung_denda(
self.tagihan, self.invoice.tgl_jatuh_tempo_sppt, self.persen_denda,
tgl_bayar)
self.denda = round_up(denda)
def hitung(self, tgl_bayar=None):
if tgl_bayar is None:
tgl_bayar = date.today()
self.hitung_pokok()
self.hitung_denda(tgl_bayar)
self.total = self.tagihan + self.denda
def do_payment(self, bank_fields, nip_pencatat, tgl_bayar=None):
if not tgl_bayar:
tgl_bayar = datetime.now()
Payment = self.get_payment_model()
bayar = self.invoice2payment()
if bayar:
ke = bayar.pembayaran_sppt_ke + 1
else:
ke = 1
bayar = Payment()
for key, value in bank_fields.items():
setattr(bayar, key, value)
bayar.kd_propinsi = self.invoice.kd_propinsi
bayar.kd_dati2 = self.invoice.kd_dati2
bayar.kd_kecamatan = self.invoice.kd_kecamatan
bayar.kd_kelurahan = self.invoice.kd_kelurahan
bayar.kd_blok = self.invoice.kd_blok
bayar.no_urut = self.invoice.no_urut
bayar.kd_jns_op = self.invoice.kd_jns_op
bayar.thn_pajak_sppt = self.invoice.thn_pajak_sppt
bayar.pembayaran_sppt_ke = ke
bayar.tgl_rekam_byr_sppt = datetime.now()
bayar.tgl_pembayaran_sppt = tgl_bayar
bayar.jml_sppt_yg_dibayar = self.total
bayar.denda_sppt = self.denda
bayar.nip_rekam_byr_sppt = nip_pencatat
self.before_save(bayar)
DBSession.add(bayar)
self.invoice.status_pembayaran_sppt = '1' # Lunas
DBSession.add(self.invoice)
DBSession.flush()
return bayar
def before_save(self, bayar):
pass
class Reversal(Query):
def __init__(self, invoice_id):
Query.__init__(self, invoice_id)
self.payment = self.invoice2payment()
def do_reversal(self):
self.payment.jml_sppt_yg_dibayar = self.payment.denda_sppt = 0
DBSession.add(self.payment)
self.invoice.status_pembayaran_sppt = '0'
DBSession.add(self.invoice)
self.before_save()
DBSession.flush()
def before_save(self):
pass
class AvailableInvoice(Query):
def __init__(self, persen_denda=2, count=10, tahun=None):
self.count = count
self.persen_denda = persen_denda
self.tahun = tahun
def get_inquiry_class(self):
return Inquiry
def show(self):
Invoice = self.get_invoice_model()
Payment = self.get_payment_model()
base_inq_cls = self.get_inquiry_class()
class Inq(base_inq_cls):
def get_invoice_model(self):
return Invoice
def get_payment_model(self):
return Payment
offset = -1
no = 0
awal = time()
while True:
durasi = time() - awal
if durasi > 10:
break
offset += 1
q = DBSession.query(Invoice).filter_by(status_pembayaran_sppt='0')
if self.tahun:
q = q.filter_by(thn_pajak_sppt=self.tahun)
q = q.offset(offset).limit(1)
inv = q.first()
if not inv:
continue
inq = Inq(invoice=inv)
if inq.is_paid():
continue
no += 1
msg = '#{} {} Pokok Rp {} + Denda Rp {} = Rp {}'.format(
str(no).zfill(2), inq.invoice_id_raw,
thousand(inq.tagihan), thousand(inq.denda),
thousand(inq.total))
print(msg)
if no == self.count:
break
from sismiop.models.default import ( from sismiop.models.default import (
ObjekPajak,
Sppt, Sppt,
PembayaranSppt, PembayaranSppt,
Kelurahan, Kelurahan,
Kecamatan, Kecamatan,
Propinsi, Propinsi,
) )
from ..sppt import ( from ..base import (
CalculateInvoice as BaseCalc,
AvailableInvoice as BaseAvailableInvoice, AvailableInvoice as BaseAvailableInvoice,
Inquiry as BaseInquiry,
Reversal as BaseReversal,
) )
class CalculateInvoice(BaseCalc): class Inquiry(BaseInquiry):
def __init__( def get_op_model(self):
self, persen_denda, propinsi, kabupaten, kecamatan, kelurahan, return ObjekPajak
blok, urut, jenis, tahun):
BaseCalc.__init__( def get_invoice_model(self):
self, Sppt, PembayaranSppt, persen_denda, propinsi, kabupaten, return Sppt
kecamatan, kelurahan, blok, urut, jenis, tahun, Kelurahan,
Kecamatan, Propinsi) def get_payment_model(self):
return PembayaranSppt
def get_kelurahan_model(self):
return Kelurahan
def get_kecamatan_model(self):
return Kecamatan
def get_propinsi_model(self):
return Propinsi
class Reversal(BaseReversal):
def get_invoice_model(self):
return Sppt
def get_payment_model(self):
return PembayaranSppt
class AvailableInvoice(BaseAvailableInvoice): class AvailableInvoice(BaseAvailableInvoice):
def __init__(self, persen_denda): def get_invoice_model(self):
BaseAvailableInvoice.__init__(self, Sppt, PembayaranSppt, persen_denda) return Sppt
def get_payment_model(self):
return PembayaranSppt
from time import time
from datetime import date
from sqlalchemy import func
import locale
from opensipkd.hitung import (
hitung_denda,
round_up,
)
from . import get_db_session
locale.setlocale(locale.LC_ALL, 'id_ID.utf8')
def thousand(n):
return locale.format('%0.f', n, True)
class Query:
def __init__(
self, Sppt, Pembayaran, Kelurahan=None, Kecamatan=None,
Propinsi=None):
self.Sppt = Sppt
self.Pembayaran = Pembayaran
self.Kelurahan = Kelurahan
self.Kecamatan = Kecamatan
self.Propinsi = Propinsi
self.DBSession = get_db_session()
def query_invoice(
self, propinsi, kabupaten, kecamatan, kelurahan, blok, urut, jenis,
tahun):
return self.DBSession.query(self.Sppt).filter_by(
kd_propinsi=propinsi, kd_dati2=kabupaten,
kd_kecamatan=kecamatan, kd_kelurahan=kelurahan, kd_blok=blok,
no_urut=urut, kd_jns_op=jenis, thn_pajak_sppt=tahun)
def query_payment(
self, propinsi, kabupaten, kecamatan, kelurahan, blok, urut, jenis,
tahun):
return self.DBSession.query(self.Pembayaran).filter_by(
kd_propinsi=propinsi, kd_dati2=kabupaten,
kd_kecamatan=kecamatan, kd_kelurahan=kelurahan, kd_blok=blok,
no_urut=urut, kd_jns_op=jenis, thn_pajak_sppt=tahun)
def invoice2payment(self, inv):
q = self.query_payment(
inv.kd_propinsi, inv.kd_dati2, inv.kd_kecamatan,
inv.kd_kelurahan, inv.kd_blok, inv.no_urut, inv.kd_jns_op,
inv.thn_pajak_sppt)
q = q.order_by(self.Pembayaran.pembayaran_sppt_ke.desc())
return q.first()
def nama_kelurahan(self, propinsi, kabupaten, kecamatan, kelurahan):
q = self.DBSession.query(self.Kelurahan).filter_by(
kd_propinsi=propinsi, kd_dati2=kabupaten,
kd_kecamatan=kecamatan, kd_kelurahan=kelurahan)
r = q.first()
return r and r.nm_kelurahan or ''
def nama_kecamatan(self, propinsi, kabupaten, kecamatan):
q = self.DBSession.query(self.Kecamatan).filter_by(
kd_propinsi=propinsi, kd_dati2=kabupaten,
kd_kecamatan=kecamatan)
r = q.first()
return r and r.nm_kecamatan or ''
def nama_propinsi(self, propinsi):
q = self.DBSession.query(self.Propinsi).\
filter_by(kd_propinsi=propinsi)
r = q.first()
return r and r.nm_propinsi or ''
def is_available(self):
return self.invoice.status_pembayaran_sppt == '1'
def is_paid(self):
return self.is_available()
def get_id(row):
return ''.join(
[row.kd_propinsi, row.kd_dati2, row.kd_kecamatan,
row.kd_kelurahan, row.kd_blok, row.no_urut, row.kd_jns_op,
row.thn_pajak_sppt])
class CalculateInvoice(Query):
def __init__(
self, Sppt, Pembayaran, persen_denda, propinsi, kabupaten,
kecamatan, kelurahan, blok, urut, jenis, tahun, Kelurahan=None,
Kecamatan=None, Propinsi=None):
Query.__init__(self, Sppt, Pembayaran, Kelurahan, Kecamatan, Propinsi)
self.persen_denda = persen_denda
self.propinsi = propinsi
self.kabupaten = kabupaten
self.kecamatan = kecamatan
self.kelurahan = kelurahan
self.blok = blok
self.urut = urut
self.jenis = jenis
self.tahun = tahun
self.invoice = self.invoice_tahun(tahun)
if self.invoice:
self.hitung()
def nama_kelurahan(self):
inv = self.invoice
return Query.nama_kelurahan(
self, inv.kd_propinsi, inv.kd_dati2, inv.kd_kecamatan,
inv.kd_kelurahan)
def nama_kecamatan(self):
inv = self.invoice
return Query.nama_kecamatan(
self, inv.kd_propinsi, inv.kd_dati2, inv.kd_kecamatan)
def nama_propinsi(self):
return Query.nama_propinsi(self, self.invoice.kd_propinsi)
def is_paid(self):
return self.total < 1
def is_available(self):
return not self.is_paid() and \
self.invoice.status_pembayaran_sppt in ('0', '1')
def invoice_tahun(self, tahun):
q = self.query_invoice(
self.propinsi, self.kabupaten, self.kecamatan, self.kelurahan,
self.blok, self.urut, self.jenis, tahun)
return q.first()
def hitung_invoice(self, invoice):
q = self.DBSession.query(
func.sum(self.Pembayaran.jml_sppt_yg_dibayar).
label('jml_sppt_yg_dibayar'),
func.sum(self.Pembayaran.denda_sppt).
label('denda_sppt')).\
filter_by(kd_propinsi=invoice.kd_propinsi,
kd_dati2=invoice.kd_dati2,
kd_kecamatan=invoice.kd_kecamatan,
kd_kelurahan=invoice.kd_kelurahan,
kd_blok=invoice.kd_blok,
no_urut=invoice.no_urut,
kd_jns_op=invoice.kd_jns_op,
thn_pajak_sppt=invoice.thn_pajak_sppt)
bayar = q.first()
jml_bayar = bayar.jml_sppt_yg_dibayar or 0
denda_lalu = bayar.denda_sppt or 0
sisa = float(jml_bayar - denda_lalu)
tagihan = round_up(invoice.pbb_yg_harus_dibayar_sppt - sisa)
kini = date.today()
bln_tunggakan, denda = hitung_denda(
tagihan, invoice.tgl_jatuh_tempo_sppt, self.persen_denda, kini)
denda = round_up(denda)
return tagihan, denda, bln_tunggakan, kini
def hitung(self):
self.tagihan, self.denda, self.bln_tunggakan, self.kini = \
self.hitung_invoice(self.invoice)
self.total = self.tagihan + self.denda
def set_paid(self):
self.invoice.status_pembayaran_sppt = '1' # Lunas
def create_payment(self, denda, tgl_bayar, bank_fields, nip_pencatat):
bayar = self.invoice2payment()
if bayar:
ke = bayar.pembayaran_sppt_ke + 1
else:
ke = 1
bayar = self.Pembayaran()
bayar.kd_propinsi = self.invoice.kd_propinsi
bayar.kd_dati2 = self.invoice.kd_dati2
bayar.kd_kecamatan = self.invoice.kd_kecamatan
bayar.kd_kelurahan = self.invoice.kd_kelurahan
bayar.kd_blok = self.invoice.kd_blok
bayar.no_urut = self.invoice.no_urut
bayar.kd_jns_op = self.invoice.kd_jns_op
bayar.thn_pajak_sppt = self.invoice.thn_pajak_sppt
bayar.pembayaran_sppt_ke = ke
bayar.tgl_rekam_byr_sppt = datetime.now()
bayar.tgl_pembayaran_sppt = tgl_bayar
bayar.jml_sppt_yg_dibayar = self.total
bayar.denda_sppt = denda
bayar.nip_rekam_byr_sppt = nip_pencatat
bayar.from_dict(bank_fields)
self.set_paid()
self.before_save(bayar)
self.DBSession.add(self.invoice)
self.DBSession.add(bayar)
self.DBSession.flush()
return bayar, ke
def before_save(self, bayar):
pass
# Override
def invoice2payment(self):
return Query.invoice2payment(self, self.invoice)
def get_id(self):
return get_id(self.invoice)
class AvailableInvoice:
def __init__(self, Sppt, Pembayaran, persen_denda=2, count=10):
self.count = count
self.Sppt = Sppt
self.Pembayaran = Pembayaran
self.persen_denda = persen_denda
def show(self):
Sppt = self.Sppt
offset = -1
no = 0
db_session = get_db_session()
awal = time()
while True:
durasi = time() - awal
if durasi > 10:
break
offset += 1
q = db_session.query(Sppt).filter_by(status_pembayaran_sppt='0')
q = q.order_by(Sppt.kd_propinsi, Sppt.kd_dati2, Sppt.kd_kecamatan,
Sppt.kd_kelurahan, Sppt.kd_blok, Sppt.no_urut,
Sppt.kd_jns_op, Sppt.thn_pajak_sppt)
q = q.offset(offset).limit(1)
row = q.first()
if not row:
continue
calc = CalculateInvoice(
self.Sppt, self.Pembayaran, self.persen_denda,
row.kd_propinsi, row.kd_dati2, row.kd_kecamatan,
row.kd_kelurahan, row.kd_blok, row.no_urut, row.kd_jns_op,
row.thn_pajak_sppt)
if calc.is_paid():
continue
invoice_id = calc.get_id()
no += 1
msg = '#{} {} Pokok Rp {} + Denda Rp {} = Rp {}'.format(
str(no).zfill(2), invoice_id, thousand(calc.tagihan),
thousand(calc.denda), thousand(calc.total))
print(msg)
if no == self.count:
break
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!