Tax return data entry program

1.確定申告用データ入力アプリ

 今年の確定申告には間に合いませんでしたが、来年の申告に備え、確定申告用のデータ作成プログラムを作成しました。

Pythonistaでのプログラムですが、画面遷移、メイン-サブ画面でのデータの受け渡しに関して、参考になるところがあるかと思います。

今年の申告データを入力し、すべての数値が、申告結果と一致することを確認済みです。

ただ、データ入力間違いや、数値以外の入力に対するエラー処理は組み込めていないので、正常なデータ入力前提での動作のみになります。

2.UI画面構成

(1)メイン画面:確定申告票の主項目 TaxAppMain.pyui

 メイン画面は、確定申告票のフォーマットに近いものとしました。

確定申告メイン画面
Screenshot

データ入力はサブ画面で行います。

「公的年金入力」ボタンで、収入等のデータ入力画面に遷移します。

「控除等入力」ボタンで、控除対象のデータ入力画面に遷移します。

各サブ画面で、データ入力後、このメイン画面に戻り、サブ画面で入力のデータを元に、最終的に、税額計算を行い、表示をします。

(2)収入入力画面:公的年金、個人年金の入力画面 TaxAppSub_inc.pyui

 このサブ画面で、収入を全て入力します。

 入力するところだけをtext_fieldにすべきでしたが、現時点では全てtext_fieldになっています。

 その辺は、まだ改良の余地ありです。

 データ入力後、「公的年金算出」「個人年金算出」ボタンを押下することで、所得計算をして表示します。

データ入力は、「入力完了」ボタン押下で、メイン画面に戻ります。

収入のデータ入力画面
Screenshot

(3)控除等入力画面:社会保険料、生命保険料等の控除対象のデータ入力 TaxAppSub_ded.pyui

 控除対象項目、及び、源泉徴収税額の入力を行います。

源泉徴収は別画面にしても良かったですが、画面を切り替えての入力の煩わしさを考え、この画面でまとめて入力するようにしました。

全ての項目を入力後、「控除額算出」ボタン押下で、各項目の計算を行い、結果を表示します。

「入力完了」ボタンでメイン画面に戻ります。

控除、源泉徴収入力画面
Screenshot

3.ソースコード

(1)メイン画面 TaxAppMain.py

import ui

import sys

#各入力情報のサブ画面クラスをインポート

from TaxAppSub_Inc import InputIncomeView

from TaxAppSub_ded import InputDeductionView

class TaxApp:

    def __init__(self):

        self.view = ui.load_view(‘TaxAppMain’)

        # 辞書型データ データ初期化

        self.d_inc:dict[str, int] = {

            ‘income’: 0, #公的年金収入

            ‘incomex’: 0, #個人年金収入

            ‘shotoku’: 0, #公的年金所得

            ‘shotokux’: 0, #個人年金所得

            ‘shotokusum’: 0 #所得合計

        }

        self.d_ded:dict[str, int] = {

            ‘social’: 0,      #社会保険料控除

            ‘insurance’: 0,   #生命保険料控除

            ‘insuranceeq’: 0, #地震保険料控除

            ‘medical’: 0,     #医療費控除

            ‘spouse’: 0,      #配偶者控除

            ‘base’: 0,        #基礎控除

            ‘dedsum’: 0,      #基礎控除

            ‘withhold’: 0

        }

        self.d_tax:dict[str, int] = {

            ‘taxinc’: 0,

            ‘taxs’: 0,

            ‘fukkou’: 0,

            ‘taxsum’: 0,

            ‘result’: 0,

            ‘taxratio1’: 1949000,

            ‘taxratio2’: 3299000

        }

        # ボタン設定 ボタン押下での関数open_inputの引数設定

        self.view[‘btn_income’].action = lambda s: self.open_income(self.d_inc, ‘収入’)

        self.view[‘btn_ded’].action = lambda s: self.open_deduction(self.d_ded, ‘控除’)

        self.refresh_labels()

    def txtnum(self, name):

        txt = self.view[name].text

        if txt == ”:

            return 0

        return int(txt.replace(‘,’, ”))

    def open_income(self, d_inc, title):

        self.d_inc[‘income’] = self.txtnum(‘lbl_income’)  

        self.d_inc[‘incomex’] = self.txtnum(‘lbl_incomex’)

        self.d_inc[‘shotoku’] = self.txtnum(‘lbl_shotoku’)

        self.d_inc[‘shotokux’] = self.txtnum(‘lbl_shotokux’)

        sub = InputIncomeView(title, self.d_inc, lambda v: self.update_income(v))

        #サブ画面起動                      

        self.nav.push_view(sub.view)

    def open_deduction(self, d_ded, title):

        self.d_ded[‘social’] = self.txtnum(‘lbl_social’)

        self.d_ded[‘insurance’] = self.txtnum(‘lbl_insurance’)

        self.d_ded[‘insuranceeq’] = self.txtnum(‘lbl_insuranceeq’)

        self.d_ded[‘medical’] = self.txtnum(‘lbl_medical’)

        self.d_ded[‘spouse’] = self.txtnum(‘lbl_spouse’)

        self.d_ded[‘base’] = self.txtnum(‘lbl_base’)

        self.d_ded[‘dedsum’] = self.txtnum(‘lbl_dedsum’)

        self.d_ded[‘withhold’] = self.txtnum(‘lbl_withhold’)

        sub = InputDeductionView(title, self.d_ded, lambda v: self.update_deduction(v))

        #サブ画面起動                      

        self.nav.push_view(sub.view)

    # 値更新

    def update_income(self, value):

        print(‘Return Value=’, value)

        self.d_inc[‘income’] = value[‘income’]

        self.d_inc[‘incomex’] = value[‘incomex’]

        self.d_inc[‘shotoku’] = value[‘shotoku’]

        self.d_inc[‘shotokux’] = value[‘shotokux’]

        self.d_inc[‘shotokusum’] = value[‘shotoku’] + value[‘shotokux’]                

        self.refresh_labels()

    def update_deduction(self, value):

        print(‘Return Value=’, value)

        self.d_ded[‘social’] = value[‘social’]

        self.d_ded[‘insurance’] = value[‘insurance’]

        self.d_ded[‘insuranceeq’] = value[‘insuranceeq’]

        self.d_ded[‘medical’] = value[‘medical’]

        self.d_ded[‘spouse’] = value[‘spouse’]

        self.d_ded[‘base’] = value[‘base’]

        self.d_ded[‘dedsum’] = value[‘social’] \

                             + value[‘insurance’] \

                             + value[‘insuranceeq’] \

                             + value[‘medical’] \

                             + value[‘spouse’] \

                             + value[‘base’]

        self.d_ded[‘withhold’] = value[‘withhold’]

        #税額算出

        taxinc = self.d_tax[‘taxinc’] = self.d_inc[‘shotokusum’] – self.d_ded[‘dedsum’]

        if taxinc <= self.d_tax[‘taxratio1’]:

            self.d_tax[‘taxs’] = int(taxinc * 0.05)

        else:

            if taxinc <= self.d_tax[‘taxratio2’]:

                self.d_tax[‘taxs’] = int(taxinc * 0.1)

        self.d_tax[‘fukkou’] = int(self.d_tax[‘taxs’] * 0.021)

        self.d_tax[‘taxsum’] = self.d_tax[‘taxs’] + self.d_tax[‘fukkou’]

        self.d_tax[‘result’] = self.d_tax[‘taxsum’] – self.d_ded[‘withhold’]        

        self.refresh_labels()

    # 値更新

    def update_value(self, key, value):

        self.data[key] = value

        self.refresh_labels()

    # 画面更新

    def refresh_labels(self):

        self.view[‘lbl_income’].text = f”{self.d_inc[‘income’]:,}”

        self.view[‘lbl_incomex’].text = f”{self.d_inc[‘incomex’]:,}”

        self.view[‘lbl_shotoku’].text = f”{self.d_inc[‘shotoku’]:,}”

        self.view[‘lbl_shotokux’].text = f”{self.d_inc[‘shotokux’]:,}”

        self.view[‘lbl_shotokusum’].text = f”{self.d_inc[‘shotokusum’]:,}”

        self.view[‘lbl_social’].text = f”{self.d_ded[‘social’]:,}”

        self.view[‘lbl_insurance’].text = f”{self.d_ded[‘insurance’]:,}”

        self.view[‘lbl_insuranceeq’].text = f”{self.d_ded[‘insuranceeq’]:,}”

        self.view[‘lbl_medical’].text = f”{self.d_ded[‘medical’]:,}”

        self.view[‘lbl_withhold’].text = f”{self.d_ded[‘withhold’]:,}”

        self.view[‘lbl_spouse’].text = f”{self.d_ded[‘spouse’]:,}”

        self.view[‘lbl_base’].text = f”{self.d_ded[‘base’]:,}”

        self.view[‘lbl_dedsum’].text = f”{self.d_ded[‘dedsum’]:,}”

        total_deduction = self.d_ded[‘dedsum’]

        self.view[‘lbl_taxinc’].text = f”{self.d_tax[‘taxinc’]:,}”

        self.view[‘lbl_taxs’].text = f”{self.d_tax[‘taxs’]:,}”

        self.view[‘lbl_fukkou’].text = f”{self.d_tax[‘fukkou’]:,}”

        self.view[‘lbl_taxsum’].text = f”{self.d_tax[‘taxsum’]:,}”

        self.view[‘lbl_result’].text = f”{self.d_tax[‘result’]:,}”        

#        taxable = self.d_inc[‘shotokusum’] – total_deduction

#        self.view[‘lbl_dedsum’].text = f”{taxable:,}”

if __name__ == ‘__main__’:

    app = TaxApp()

    nav = ui.NavigationView(app.view)

    app.nav = nav

    if sys.platform == ‘darwin’:

        nav.present(‘panel’)  # Mac快適

    else:

        nav.present(‘fullscreen’)  # iOS本番

(2)収入入力画面 TaxAppSub_Inc.py

import ui

class InputIncomeView:

    def __init__(self, title, initial_value, callback):

        self.callback = callback

        print(‘Sub_Inc:initial_value=’,initial_value)

        self.ini_val = initial_value

        print(‘Sub_Inc:ini_val=’, self.ini_val)

        self.view = ui.load_view(‘TaxAppSub_Inc’)

        self.view.name = title

#        self.view[‘txt_amount’].text = str(initial_value)

        self.view[‘txt_amountinc’].text = str(self.ini_val[‘income’])

        self.view[‘txt_amountincx’].text = str(self.ini_val[‘incomex’])

        self.view[‘txt_shotoku’].text = str(self.ini_val[‘shotoku’])

        self.view[‘txt_shotokux’].text = str(self.ini_val[‘shotokux’])

        self.view[‘btn_ok’].action = self.on_ok

        self.view[‘btn_calcInc’].action = self.CalcIncome

        self.view[‘btn_calcIncx’].action = self.CalcIncomex

        #収入=>所得算出テーブル

        #上限, 係数, 加算額, 控除上限

        self.INS2SHOTOKU_TBL = [

            (600001, 0, 0),

            (1300000, 1.0, 600000),

            (4100000, 0.75, 275000),

            (7700000, 0.15, 685000),

            (10000000, 0.05, 1455000),

            (99999999, 1.0, 1955000)

        ]

    def calcShotoku(self, amount):

        for ins_limit, rate, sub in self.INS2SHOTOKU_TBL:

            if amount < ins_limit:

                value = int(amount * rate – sub)

                return value

    def CalcIncome(self, sender):

        amountinc = int(self.view[‘txt_kosei’].text) + int(self.view[‘txt_nrk’].text) + int(self.view[‘txt_r’].text)  

        shotoku = self.calcShotoku(amountinc)

        self.view[‘txt_amountinc’].text = str(amountinc)

        self.view[‘txt_shotoku’].text = str(shotoku)

    def CalcIncomex(self, sender):

#        amountincx = self.ini_val[‘income’] + self.ini_val[‘incomex’]

        amountincx = int(self.view[‘txt_my1inc’].text) + int(self.view[‘txt_my2inc’].text) + int(self.view[‘txt_coopinc’].text)  

        keihi = int(self.view[‘txt_my1keihi’].text) + int(self.view[‘txt_my2keihi’].text) + int(self.view[‘txt_coopkeihi’].text)  

        shotokux = amountincx – keihi

        self.view[‘txt_amountincx’].text = str(amountincx)

        self.view[‘txt_shotokux’].text = str(shotokux)

    def on_ok(self, sender):

        self.ini_val[‘income’] = int(self.view[‘txt_amountinc’].text.replace(‘,’, ”))

        self.ini_val[‘incomex’] = int(self.view[‘txt_amountincx’].text.replace(‘,’, ”))

        self.ini_val[‘shotoku’] = int(self.view[‘txt_shotoku’].text.replace(‘,’, ”))

        self.ini_val[‘shotokux’] = int(self.view[‘txt_shotokux’].text.replace(‘,’, ”))

        self.callback(self.ini_val)

        self.view.navigation_view.pop_view()

(3)控除等入力画面 TaxAppSub_ded.py

import ui

class InputDeductionView:

    def __init__(self, title, initial_value, callback):

        self.callback = callback

        self.ini_val = initial_value

        self.view = ui.load_view(‘TaxAppSub_ded’)

        self.view.name = title

        self.view[‘txt_socsum’].text = str(self.ini_val[‘social’])

        self.view[‘txt_inssum’].text = str(self.ini_val[‘insurance’])

        self.view[‘txt_inseqsum’].text = str(self.ini_val[‘insuranceeq’])

        self.view[‘txt_medsum’].text = str(self.ini_val[‘medical’])

        self.view[‘txt_spouse’].text = str(self.ini_val[‘spouse’])

        self.view[‘txt_base’].text = str(self.ini_val[‘base’])        

        self.view[‘btn_ok’].action = self.on_ok

        self.view[‘btn_calc’].action = self.CalcDeduction

        #新契約保険料控除額算出テーブル

        #上限, 係数, 加算額, 控除上限

        self.NEWINS_TBL = [

            (20000, 1.0,     0,     40000),

            (40000, 0.5, 10000,     40000),

            (80000, 0.25,20000,     40000),

            (99999999, 0,  40000,   40000)

        ]

        #旧契約保険料控除額算出テーブル

        self.OLDINS_TBL = [

            (25000, 1.0,     0,     50000),

            (50000, 0.5, 12500,     50000),

            (100000,0.25,25000,     50000),

            (99999999,0,  50000,    50000)

        ]

        #地震保険料控除額算出テーブル

        self.EQINS_TBL = [

            (50000, 1.0, 0, 50000),

            (99999999,0,50000,50000)

        ]

    #保険料控除額算出function by table

    def calcIns_by_tbl(self, amount, table):

        for limit, rate, add, maxval in table:

            if amount <= limit:

                value = int(amount * rate + add)

                return min(value, maxval)

    def txtnum(self, name):

        txt = self.view[name].text

        if txt == ”:

            return 0

        return int(txt.replace(‘,’, ”))

    def CalcDeduction(self, sender):

        socsum = self.txtnum(‘txt_nsoc’) \

         + self.txtnum(‘txt_h1soc’) + self.txtnum(‘txt_h2soc’) \

         + self.txtnum(‘txt_psoc’)

        old_ins = self.calcIns_by_tbl(self.txtnum(‘txt_oldins’), self.OLDINS_TBL)  

        new_ins = self.calcIns_by_tbl(self.txtnum(‘txt_newins’), self.NEWINS_TBL)

        inssum = old_ins + new_ins + self.txtnum(‘txt_nins’)

        inseqsum = self.calcIns_by_tbl(self.txtnum(‘txt_inseqsum’), self.EQINS_TBL)

        medsum = self.txtnum(‘txt_1stmed’) + self.txtnum(‘txt_2ndmed’)

        if medsum < 100000:

  medsum = 0

        else:

  medsum -= 100000

        spouse = self.txtnum(‘txt_spouse’)

        base = self.txtnum(‘txt_base’)

        print(‘socsum,inssum,medsum,spouse,base=’,socsum,inssum,medsum,spouse,base)

        withhold = self.txtnum(‘txt_wh0’) + self.txtnum(‘txt_whr’) + self.txtnum(‘txt_whnrk’)      

        self.view[‘txt_socsum’].text = str(socsum)

        self.view[‘txt_inssum’].text = str(inssum)

        self.view[‘txt_inseqsum’].text = str(inseqsum)

        self.view[‘txt_medsum’].text = str(medsum)

        self.view[‘txt_spouse’].text = str(spouse)

        self.view[‘txt_base’].text = str(base)

        self.view[‘txt_whsum’].text = str(withhold)

    def on_ok(self, sender):       

        self.ini_val[‘social’] = self.txtnum(‘txt_socsum’)

        self.ini_val[‘insurance’] = self.txtnum(‘txt_inssum’)

        self.ini_val[‘insuranceeq’] = self.txtnum(‘txt_inseqsum’)

        self.ini_val[‘medical’] = self.txtnum(‘txt_medsum’)

        self.ini_val[‘spouse’] = self.txtnum(‘txt_spouse’)

        self.ini_val[‘base’] = self.txtnum(‘txt_base’)

        self.ini_val[‘withhold’] = self.txtnum(‘txt_whsum’)                

        self.callback(self.ini_val)

        self.view.navigation_view.pop_view()


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です