LoginSignup
4
3

More than 5 years have passed since last update.

ExcelテンプレートエンジンJETTを利用して請求書を出力しよう

Last updated at Posted at 2016-06-13

(お客様の声)

システム(入力画面)はあるのに「現場では見積書・請求書・納品書はExcelを使って手動で作成している」
この画面の端っこに「帳票出力」ボタンがあって押すと出力できたら良いなぁ

はじめに

お客様には提案したいけど、導入が難しいと思ってしまっているエンジニア(Java)に、きっと朗報なナレッジとなります。「JETT」は、ちょっとしたルールを理解することで、ある程度の想像のつく多くの帳票をテンプレート化することができ、そして動的に出力することができます。

以下は、「請求書」をテンプレート化し、データを受け渡し変換出力したイメージとなります。

INVOICE_IMAGE.png
サンプルコードは以下よりダウンロードできます。
jett-example
実際にダウンロードし動かしながら、ご確認ください。

ExcelテンプレートエンジンJETTを利用してピボットテーブルでグラフを表示しよう」の記事も確認ください。

帳票変換処理のコード

変換処理で使用するJETTのクラスは、この「ExcelTransformerクラス」だけであり、
transformメソッドを呼んでいます。

ReportMaker.java
package com.github.k3286.report;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;

import net.sf.jett.transform.ExcelTransformer;

public class ReportMaker {

    /**
     * パラメータと、テンプレートファイル名を指定し、帳票変換を行う
     * @param params パラメータ
     * @param templateName テンプレートファイル名
     * @return 変換したWorkbook
     */
    public static Workbook toReport(Map<String, Object> params, String templateName) {
        Workbook workbook = null;
        InputStream is = null;
        try {
            is = ReportMaker.class.getResourceAsStream("/" + templateName);
            ExcelTransformer transformer = new ExcelTransformer();
            workbook = transformer.transform(is, params);
        } catch (InvalidFormatException | IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return workbook;
    }
}

動作させるテストクラス

請求書に表示するデータを設定しています、明細行も一緒に設定しています。
特別、こちらについては工夫は必要ありません。
変換処理は、データを「ReportMaker.toReport()メソッド」に渡してるだけです。

InvoiceMakerTest.java
package com.github.k3286.report;

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.poi.ss.usermodel.Workbook;
import org.junit.Test;

import com.github.k3286.dto.Invoice;
import com.github.k3286.dto.InvoiceDetail;

public class InvoiceMakerTest {

    private static BigDecimal TAX_RATE = new BigDecimal(0.08);

    /**
     * 請求書の出力デモ
     * @throws Exception
     */
    @Test
    public void invoice_test() throws Exception {

        Invoice inv = new Invoice();
        inv.setInvoiceNo("INV-00000001");
        inv.setClientPostCode("〒123-3333");
        inv.setClientAddress("東京都品川区東五反田1丁目6−3 東京建物五反田ビル 108F");
        inv.setClientName("株式会社 松上電気");
        inv.setSalesRep("営業 太郎");
        inv.setInvoiceDate(new Date());

        // 明細行は5行にしておく
        for (int idx = 1; idx <= 5; idx++) {
            InvoiceDetail dtl = new InvoiceDetail();
            dtl.setItemName("サンプル明細ですよ " + idx);
            dtl.setUnitCost(BigDecimal.valueOf(10000));
            dtl.setQuantity(Double.valueOf(idx));
            dtl.setAmt(dtl.getUnitCost().multiply(//
                    BigDecimal.valueOf(dtl.getQuantity())));
            inv.getDetails().add(dtl);
        }
        BigDecimal total = BigDecimal.ZERO;
        for (InvoiceDetail dtl : inv.getDetails()) {
            total = total.add(dtl.getAmt());
        }
        // 立替金
        inv.setAdvancePaid(BigDecimal.valueOf(10800));
        // 税額
        inv.setTaxAmt(total.multiply(TAX_RATE));
        // 請求額(税込)
        inv.setInvoiceAmtTaxin(total.add(inv.getTaxAmt()).add(inv.getAdvancePaid()));
        // 備考
        inv.setNote("これは備考です、サンプルとして備考を記述し、"
                + "そして帳票に出力をしてみました。"
                + "折り返してくれるといいのですが、どうでしょうか");

        // 帳票変換
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("inv", inv);

        Workbook workbook = ReportMaker.toReport(map, "template_invoice.xlsx");

        // ファイル出力
        final String outPath = "output_invoice.xlsx";
        try (FileOutputStream fileOut = new FileOutputStream(outPath)) {
            workbook.write(fileOut);
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

帳票テンプレートで使用しているタグ

請求書のテンプレートファイルは「template_invoice.xlsx」です。
今回テンプレートファイルで使用するタグを説明します。
※ 詳細は「The JETT Tag Library」

タグ 用途 使用箇所 備考
<jt:forEach> リストを展開し各要素を出力 明細 サンプルは、limitに10を指定している。展開の行数を指定する。帳票の明細行が固定と決まっており、印刷イメージ(改ページ)を崩したくない場合に利用する
$[SUM(セル)] リストを展開したあとの数値の合計に使用する。指定したセルを基準に、展開されたセルまでを動的に数式化しSUM関数の引数に設定される 小計 $[SUM(Y26)] ⇒ SUM(Y26:Y30)

応用へ

ReportMaker.java(抜粋)
ReportMaker.class.getResourceAsStream("/" + templateName);

は、classes配下にあるテンプレートファイルを見ることになります。
この場合は、アプリケーションに組み込んだ形となるため、
テンプレートファイルの変更のたびに、再ビルドが必要となります。
運用を考慮すると、管理ユーザにとって大変です。

テンプレートファイルを外で管理する方法を考えます。
・テンプレートファイルを特定の物理パスに配置し、読み込む。
・テンプレートファイルをDBに格納し、読み込む。
・Google Driveにテンプレートファイルを配置し、読み込む。(ただしオンライン)
・etc.

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3