2009年9月19日土曜日

Drools で所得税額計算

Droolsの練習の一環として、国税庁のサイトの所得税率のページを見ながら、以下のようなルール定義ファイルを書いてみた。

package com.sample

function long trunc1000(long value) {
 return value / 1000 * 1000;
}

function long zeigaku(long shotoku, int zeiritsu, int kojo) {
 return trunc1000(shotoku) * zeiritsu / 100 - kojo;
}

function boolean inRange(long shotoku, long lower, long upper) {
    return lower < shotoku && shotoku <= upper;
}

function void print(long shotoku, int zeiritsu, int kojo) {
 System.out.println(
     String.format("所得:%1$,10d -> 税額:%2$,9d", 
      shotoku, zeigaku(shotoku, zeiritsu, kojo)));
} 

rule "195万円以下"
  when
    $shotoku: Shotoku(name == "所得", $v: value)
    eval (trunc1000($v)<=1950000)
  then
    print($v, 5, 0);
end

rule "330万円以下"
  when
    $shotoku: Shotoku(name == "所得", $v: value)
    eval (inRange(trunc1000($v), 1950000, 3300000))
  then
    print($v, 10, 97500);
end

rule "695万円以下"
  when
    Shotoku(name == "所得", $v:value)
    eval (inRange(trunc1000($v), 3300000, 6950000))
  then
    print($v, 20, 427500);
end

rule "900万円以下"
  when
    Shotoku(name == "所得", $v:value)
    eval (inRange(trunc1000($v), 6950000, 9000000))
  then
    print($v, 23, 636000);
end

rule "1800万円以下"
  when
    Shotoku(name == "所得", $v:value)
    eval (inRange(trunc1000($v), 9000000, 18000000))
  then
    print($v, 33, 1536000);
end

rule "1800万円超"
  when
    Shotoku(name == "所得", $v:value)
    eval(trunc1000($v) > 18000000)
  then
    print($v, 40, 2796000);
end
これを以下のようなJava コードで実行してみると・・・
    private static void insertShotoku(WorkingMemory wm, long shotoku) {
     wm.insert(new Shotoku(shotoku));
    }

    public static final void main(String[] args) {
        try {
・・・略
           WorkingMemory wm = ruleBase.newStatefulSession();
                   
            insertShotoku(wm, 1000000);
            insertShotoku(wm, 1950000);
            insertShotoku(wm, 1950999);
            insertShotoku(wm, 1951000);
            insertShotoku(wm, 3300000);
            insertShotoku(wm, 6950000);
            insertShotoku(wm, 9000000);
            insertShotoku(wm, 18000000);
            insertShotoku(wm, 18001000);

            wm.fireAllRules();      
・・・略
次のようなコンソール出力を得る
所得:18,001,000 -> 税額: 4,404,400
所得:18,000,000 -> 税額: 4,404,000
所得: 9,000,000 -> 税額: 1,434,000
所得: 6,950,000 -> 税額:   962,500
所得: 3,300,000 -> 税額:   232,500
所得: 1,951,000 -> 税額:    97,600
所得: 1,950,999 -> 税額:    97,500
所得: 1,950,000 -> 税額:    97,500
所得: 1,000,000 -> 税額:    50,000
出てきた税額はまずまず合ってるっぽい。

上で使った税率は平成21年度現在のものだけど、同サイトでは平成18年以前の速算表も載っている。やはり、こういった税率やらを含む制度はしょっちゅう変わるわけで、こんなのをいちいち Javaソースにハードコードするのも馬鹿馬鹿しい。ルールはルールで別途外部のリソースとして置いて、実行時に読み込むような形にするべきなんだろうと思う。

ところで、理想的にはユーザ側のドメインエキスパートがルール定義ファイルを書くのが良いと思うのだけど、どの程度こういった DSL に対応できるのだろう・・・?個人差はあるだろうけど、まったくのプログラム未経験のビジネスパーソンには、ちょっと難しいような気もする。

それと、自分が Drools を触り始めたばかりで、まだまだ良く分かっていないという事もあるのだろうけど、どうもいまいち Java コードとルール定義がスッキリ分離しきれない気がする。Javaコードを書くプログラマとルールを定義するビジネスパーソンの間で、上手いこと住み分けと協調をやってかないと、かえって面倒くさい事になりそうな気がしないでもない。何か評価の定まったベストプラクティス的なものがあればいいんだけど。

0 件のコメント:

コメントを投稿