query.py 10.7 KB
from datetime import (
    datetime,
    date,
)
from sqlalchemy import func
from .db_tools import (
    hitung_denda,
    sppt2nop,
)
from .tools import round_up


class Query:
    def __init__(self, models, DBSession):
        self.models = models
        self.DBSession = DBSession

    def query_invoice(
            self, propinsi, kabupaten, kecamatan, kelurahan, blok, urut, jenis,
            tahun):
        return self.DBSession.query(self.models.Invoice).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.models.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.models.Pembayaran.pembayaran_sppt_ke.desc())
        return q.first()

    def nama_kelurahan(self, propinsi, kabupaten, kecamatan, kelurahan):
        q = self.DBSession.query(self.models.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.models.Kecamatan).filter_by(
            kd_propinsi=propinsi, kd_dati2=kabupaten,
            kd_kecamatan=kecamatan)
        r = q.first()
        return r and r.nm_kecamatan or ''

    def nama_kabupaten(self, propinsi, kabupaten):
        q = self.DBSession.query(self.models.Kabupaten).filter_by(
            kd_propinsi=propinsi, kd_dati2=kabupaten)
        r = q.first()
        return r and r.nm_dati2 or ''

    def nama_propinsi(self, propinsi):
        q = self.DBSession.query(self.models.Propinsi). \
            filter_by(kd_propinsi=propinsi)
        r = q.first()
        return r and r.nm_propinsi or ''

    def objek_pajak(
            self, propinsi, kabupaten, kecamatan, kelurahan, blok, urut, jenis):
        q = self.DBSession.query(self.models.ObjekPajak).filter_by(
            kd_propinsi=propinsi, kd_dati2=kabupaten,
            kd_kecamatan=kecamatan, kd_kelurahan=kelurahan, kd_blok=blok,
            no_urut=urut, kd_jns_op=jenis)
        return q.first()

    def is_paid(self, invoice):
        return invoice.status_pembayaran_sppt == '1'


class CalculateInvoice(Query):
    def __init__(
            self, models, DBSession, persen_denda, propinsi, kabupaten,
            kecamatan, kelurahan, blok, urut, jenis, tahun):
        Query.__init__(self, models, DBSession)
        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)
        self.tagihan = self.denda = self.bln_tunggakan = self.kini = 0
        self.pembayaran_ke = self.total = 0
        self.discount = self.discount_pokok = self.discount_denda = self.denda_sblm_diskon = 0
        self.tgl_bayar = datetime.now()
        if self.invoice and self.invoice.status_pembayaran_sppt == '0':
            self.hitung()
            self.paid = self.is_paid()

    def invoice_id(self):
        return "{}.{}-{}.{}-{}.{}-{} {}".format(
            self.propinsi, self.kabupaten, self.kecamatan, self.kelurahan,
            self.blok, self.urut, self.jenis, self.tahun)

    def invoice2dict(self):
        row = self.invoice
        j = []
        if row.blok_kav_no_wp_sppt:
            j.append('Blok {}'.format(row.blok_kav_no_wp_sppt))
        if row.rt_wp_sppt:
            j.append('RT {}'.format(row.rt_wp_sppt))
        if row.rw_wp_sppt:
            j.append('RW {}'.format(row.rw_wp_sppt))
        return dict(
            jatuh_tempo=str(row.tgl_jatuh_tempo_sppt),
            nm_wp=row.nm_wp_sppt,
            jln_wp=row.jln_wp_sppt,
            jln_wp_2=' '.join(j),
            kelurahan_wp=row.kelurahan_wp_sppt,
            kota_wp=row.kota_wp_sppt,
            kd_pos_wp=row.kd_pos_wp_sppt and row.kd_pos_wp_sppt or '00000',
            luas_bumi=row.luas_bumi_sppt,
            luas_bng=row.luas_bng_sppt)

    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.models.Pembayaran.jml_sppt_yg_dibayar)
                .label('jml_sppt_yg_dibayar'),
            func.sum(self.models.Pembayaran.denda_sppt)
                .label('denda_sppt'),
            func.max(self.models.Pembayaran.pembayaran_sppt_ke)
                .label('ke')). \
            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)
        ke = bayar.ke and bayar.ke + 1 or 1
        return tagihan, denda, bln_tunggakan, kini, ke

    def hitung(self):
        self.tagihan, self.denda, self.bln_tunggakan, self.kini, \
        self.pembayaran_ke = self.hitung_invoice(self.invoice)
        self.total = self.tagihan + self.denda
        if self.total > 0:
            self.hitung_discount()
            self.total = self.total - self.discount

    def hitung_discount(self):
        pass

    def to_dict(self):
        d = self.invoice2dict()
        d.update(
            dict(
                pokok=self.tagihan,
                denda=self.denda,
                total=self.total,
                ke=self.pembayaran_ke,
                kelurahan_op=self.nama_kelurahan(),
                kecamatan_op=self.nama_kecamatan(),
                kota_op=self.nama_kabupaten(),
                propinsi_op=self.nama_propinsi()))
        op = self.objek_pajak()
        if op:
            j = []
            if op.blok_kav_no_op:
                j.append('Blok {}'.format(op.blok_kav_no_op))
            if op.rt_op:
                j.append('RT {}'.format(op.rt_op))
            if op.rw_op:
                j.append('RW {}'.format(op.rw_op))
            d.update(dict(jln_op=op.jalan_op, jln_op_2=' '.join(j)))
        else:
            d.update(dict(jln_op='-', jln_op_2='-'))
        return d

    def is_paid(self):
        return Query.is_paid(self, self.invoice) or self.total <= 0

    def set_paid(self):
        self.invoice.status_pembayaran_sppt = '1'  # Lunas

    def create_payment(self, tgl_bayar, bank_fields, nip_pencatat):
        bayar = self.models.Pembayaran()
        bayar.kd_propinsi = self.propinsi
        bayar.kd_dati2 = self.kabupaten
        bayar.kd_kecamatan = self.kecamatan
        bayar.kd_kelurahan = self.kelurahan
        bayar.kd_blok = self.blok
        bayar.no_urut = self.urut
        bayar.kd_jns_op = self.jenis
        bayar.thn_pajak_sppt = self.tahun
        bayar.pembayaran_sppt_ke = self.pembayaran_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.denda_sblm_diskon = self.denda_sblm_diskon
        bayar.discount = self.discount
        bayar.discount_pokok = self.discount_pokok
        bayar.discount_denda = self.discount_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

    def before_save(self, bayar):
        pass

    # Override
    def invoice2payment(self):
        return Query.invoice2payment(self, self.invoice)

    # Override
    def nama_kelurahan(self):
        return Query.nama_kelurahan(self, self.propinsi, self.kabupaten,
                                    self.kecamatan, self.kelurahan)

    # Override
    def nama_kecamatan(self):
        return Query.nama_kecamatan(self, self.propinsi, self.kabupaten,
                                    self.kecamatan)

    # Override
    def nama_kabupaten(self):
        return Query.nama_kabupaten(self, self.propinsi, self.kabupaten)

    # Override
    def nama_propinsi(self):
        return Query.nama_propinsi(self, self.propinsi)

    # Override
    def objek_pajak(self):
        return Query.objek_pajak(self, self.propinsi, self.kabupaten,
                                 self.kecamatan, self.kelurahan, self.blok, self.urut,
                                 self.jenis)


############
# Reversal #
############
class Reversal(Query):
    def __init__(
            self, models, DBSession, propinsi, kabupaten, kecamatan, kelurahan,
            blok, urut, jenis, tahun):
        Query.__init__(self, models, DBSession)
        q = self.query_invoice(
            propinsi, kabupaten, kecamatan, kelurahan, blok, urut, jenis,
            tahun)
        self.invoice = q.first()
        if not self.invoice:
            return
        self.payment = self.invoice2payment()

    def invoice2payment(self):
        return Query.invoice2payment(self, self.invoice)

    def set_unpaid(self):
        self.invoice.status_pembayaran_sppt = '0'
        self.DBSession.add(self.invoice)
        if self.payment:
            self.payment.jml_sppt_yg_dibayar = 0
            self.payment.denda_sppt = 0
            self.payment.denda_sblm_diskon = 0
            self.payment.discount = 0
            self.payment.discount_pokok = 0
            self.payment.discount_denda = 0
            self.DBSession.add(self.payment)
        self.DBSession.flush()
        return self.payment