processor.py 5.48 KB


import importlib
import logging
import multiprocessing
import re
from ISO8583.ISO8583 import ISO8583
from opensipkd.iso8583.bjb.pbb.structure import (
    INQUIRY_CODE, INVOICE_PROFILE, PAYMENT_CODE, 
    RC_ALREADY_PAID, RC_NOT_AVAILABLE, RC_INSUFFICIENT_FUND, RC_LINK_DOWN,
    RC_INVALID_NUMBER, RC_ALREADY_PAID, RC_NOT_AVAILABLE, RC_INSUFFICIENT_FUND)
# from .models import DBSession, get_connection
# from opensipkd.tools import FixLength
from .mpp import get_connection
log = logging.getLogger(__name__)
from opensipkd.string import FixLength


class ISO8583Processor:
    def __init__(self, req_queue, resp_queue, db_config=None):
        self.request_queue = req_queue
        self.response_queue = resp_queue
        self.db_config = db_config

    def start(self):
        while True:
            filename, data = self.request_queue.get()
            response = self.process_file(filename, data, self.db_config)
            self.response_queue.put((filename, response))

    def get_bit7(self):
        from datetime import datetime
        now = datetime.now()
        return now.strftime('%m%d%H%M%S')  # MMDDhhmmss format

    def process_file(self, filename, data, db_config):
        import time
        start_time = time.time()
        # Ensure DBSession is bound in this process
        # print(f"[process_file] db_config: {db_config}")

        iso = ISO8583(iso=data)
        print(iso.showBitmap())
        bit39 = '00'
        mti = iso.getMTI() if iso.getMTI() else '0000'
        log.info(f"MTI detected: {mti}")
        response = b''
        if mti == '0800':
            log.info(f"Handling network management MTI: {mti}")
            iso.setMTI('0810')

        elif mti in ('0200', '0210'):
            logging.info(f"Handling transaction MTI: {mti}")
            func = iso.getBit(3) if iso.getBit(3) else '000000'
            invid = iso.getBit(61) if iso.getBit(37) else None
            invoice_id = re.sub(r'\D', '', invid) if invid else '000000'
            iso.setMTI('0210')
            if len(invoice_id) < 22:
                bit39 = '76'
            else:
                if db_config:
                    get_connection(db_config)
                modu = importlib.import_module(
                    f"sismiop.services.{db_config.get('module')}")

                inq = modu.Inquiry(invoice_id=invoice_id)
                if not inq.invoice:
                    bit39 = RC_NOT_AVAILABLE
                else:
                    inq.hitung()
                    if inq.total < 1:
                        bit39 = RC_ALREADY_PAID
                    elif func == PAYMENT_CODE:
                        amount = iso.getBit(4) if iso.getBit(4) else '0'
                        if int(amount) != inq.total:
                            bit39 = RC_INSUFFICIENT_FUND
                    elif func == INQUIRY_CODE:
                        iso.setBit(4, inq.total)
                        inv = inq.invoice
                        invoice_profile = FixLength(INVOICE_PROFILE)
                        invoice_profile.set('Propinsi', inv.kd_propinsi)
                        invoice_profile.set('Kabupaten', inv.kd_dati2)
                        invoice_profile.set('Kecamatan', inv.kd_kecamatan)
                        invoice_profile.set('Kelurahan', inv.kd_kelurahan
                            if inv.kd_kelurahan else '000')
                        invoice_profile.set('Blok', inv.kd_blok)
                        invoice_profile.set('Urut', inv.no_urut)
                        invoice_profile.set('Jenis', inv.kd_jns_op)
                        invoice_profile.set('Tahun', inv.thn_pajak_sppt)
                        invoice_profile.set('Nama', inv.nm_wp_sppt)
                        invoice_profile.set('Lokasi', inq.get_alamat_op())
                        invoice_profile.set('Nama Kelurahan', inq.get_kelurahan_op())
                        invoice_profile.set('Nama Kecamatan', inq.get_kecamatan_op())
                        invoice_profile.set('Nama Propinsi', inq.get_propinsi_op())
                        invoice_profile.set('Luas Tanah', inv.luas_bumi_sppt)
                        invoice_profile.set('Luas Bangunan', inv.luas_bng_sppt)
                        invoice_profile.set(
                            'Jatuh Tempo', inv.tgl_jatuh_tempo_sppt.strftime('%Y%m%d'))
                        invoice_profile.set('Tagihan', inq.tagihan)
                        invoice_profile.set('Denda', inq.denda)
                        invoice_profile.set('Total Bayar', inq.total)
                        invoice_profile.set('Discount', inq.discount)
                        iso.setBit(61, invoice_profile.get_raw())

                    else:
                        bit39 = '76'

        elif mti in ('0400', '0420'):
            logging.info(f"Handling reversal MTI: {mti}")
            response = b'RESP:0400/0420'  # Add bit 7, 4, 62, 39 as needed
        else:
            logging.warning(f"Unknown MTI: {mti}")
            response = b'UNKNOWN MTI'
        if response == b'UNKNOWN MTI':
            logging.info(f"Removed unprocessable file: {filename}")
            return response
        else:
            iso.setBit(7, self.get_bit7())
            iso.setBit(39, bit39)
            response = iso.getRawIso()
            log.info(
                f"[WRITE] Prepared response for {filename}, data: {response.hex() if isinstance(response, bytes) else response}")
            return response
        end_time = time.time()
        elapsed = end_time - start_time
        log.info(
            f"[PERF] Processed {filename} in {elapsed:.3f} seconds (MTI={mti})")