FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

書類送付状生成デモの作成

前回のはがき宛名面の作成デモに続いて,書類送付状を作成するデモを作成しました。

実用的にも使えると思いますので,よかったら使ってみてください。

テンプレートの作成

まずは,オフィスソフトを利用して,帳票のレイアウトをデザインします。

今回は,長形3号の窓付き封筒で使えるように宛先欄を左上に配置しました。 Mac OS X 用の表計算ソフト Numbers を使用して元原稿を作成し,PDF形式で書き出しました。

次に,Adobe Acrobat Professional で作成したPDFを開き,テキストを動的に埋め込む位置にフォーム・フィールドを配置していきます。

基本的には,フォント・フォントサイズ・表示色などの表示属性をこの時決めて設定しますが, 帳票生成時にプログラムから指定することもできます。

テーブル形式のフィールドを配置する際には,基準となるフィールドを配置してから,「複数のフィールドを配置...」で必要な数だけ複製します。

以上で,テンプレートが完成しました。

因みに Field Reports では,フォーム・フィールドをテキストの表示位置やフォント指定などの属性を取得するためのプレース・フォルダとして利用しているにすぎません。テキストを配置した後は削除され,最終的に作成される帳票には残りません。

プログラムの作成

今回もフレームワークとしてweb2pyを使用しました。 controller部のコードを以下に示します。

「if form.accepts(request.vars):」以降で Field Reports に渡すパラメータを組み立てています。 基本的には,Webのフォームにつけた名前とPDFテンプレートに配置したフィールドの名前を一致させているので, form.varsの値がそのまま使えますが,テーブル形式の部分はリスト形式にする必要があるので, この部分の変換を行なっています。

render関数の中では,テンプレートの場所などその他のパラメータを追加して実際に Field Reports のAPIを呼び出しています。

# coding: utf8

from gluon.contrib import simplejson
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
import tools

def index():
    def docinput(num):
       return TR(TD(INPUT(_name='_no'+str(num), _size=5)),
                 TD(INPUT(_name='_document'+str(num), _size=60)),
                 TD(INPUT(_name='_count'+str(num), _size=5)))
    form = FORM(
        UL(LI(LABEL(u'日付'), INPUT(_name="date", _value="")),
           FIELDSET(LEGEND(u'宛先'),
               LI(LABEL(u'郵便番号'), INPUT(_name='to_post', _size=8)),
               LI(LABEL(u'住所1'), INPUT(_name='to_address1', _size=30)),
               LI(LABEL(u'住所2'), INPUT(_name='to_address2', _size=30)),
               LI(LABEL(u'会社名'), INPUT(_name='to_company', _size=30)),
               LI(LABEL(u'氏名'), INPUT(_name='to_name', _size=30))),
           FIELDSET(LEGEND(u'差出人'),
               LI(LABEL(u'郵便番号'), INPUT(_name='from_post', _size=8)),
               LI(LABEL(u'住所1'), INPUT(_name='from_address1', _size=30)),
               LI(LABEL(u'住所2'), INPUT(_name='from_address2', _size=30)),
               LI(LABEL(u'会社名'), INPUT(_name='from_company', _size=30)),
               LI(LABEL(u'氏名'), INPUT(_name='from_name', _size=30)),
               LI(LABEL(u'連絡先1'), INPUT(_name='from_contact1', _size=30)),
               LI(LABEL(u'連絡先2'), INPUT(_name='from_contact2', _size=30))),
           FIELDSET(LEGEND(u'送付物'),
               TABLE(
                   TR(TH(u'No.'), TH(u'書類名'), TH(u'部数')),
                   docinput(0), docinput(1), docinput(2), docinput(3),
                   docinput(4), docinput(5), docinput(6), docinput(7),
                   docinput(8), docinput(9), docinput(10))),
           LI(INPUT(_type='submit', _value='帳票出力'),
              INPUT(_type='reset', _value='リセット'), _align='right'), _id="simple"))

    if form.accepts(request.vars):
        response.flash = u'入力を受け付けました'
        context = form.vars
        context['no'] = [form.vars['_no'+str(i)] for i in range(11)]
        context['document'] = [form.vars['_document'+str(i)] for i in range(11)]
        context['count'] = [form.vars['_count'+str(i)] for i in range(11)]
        response.headers['Content-Type'] = 'application/pdf'
        response.headers['Content-Disposition'] = 'attachment; filename="cover.pdf"'
        return render(context)
    elif form.errors:
        response.flash = u'入力に誤りがあります'
    else:
        response.flash = u'フォームに入力してください'
    return dict(form=form)

def render(context):
    import os
    from field import reports
    import gluon.fileutils
    settings = {
        'template-root': os.path.join(gluon.fileutils.abspath('applications',
            request.application), 'resources'),
    }
    template = 'templates/sofu.pdf'
    params = {
        'settings': settings,
        'template': template,
        'context': context,
    }
    reports.set_defaults({})
    reports.set_log_level(3)
    return reports.renders(params)

実行例

以下に実際の実行例を示します。

参照

書類送付状生成デモの改造