弁当注文システムをアップデート

先日作った弁当注文システムを、必要あってアップデートさせました。いえね、注文がいつしめきられたかわからないことによる悲劇が幾度か繰り返されたらしいと聞きましたものですから。

言語はPython。標準ライブラリのみで動きます。

index.cgi
#! /usr/bin/env python
# -*- coding: utf-8-unix; mode: python -*-

import cgi
import cgitb; cgitb.enable()
import sys
import locale
import datetime
import random
import hashlib
import sqlite3
import re

encode = u'utf-8'
pagetitle = u'弁当注文システム'
menuuri = u'http://www.pentacom.jp/itachoco/'
dailyuri = u'http://www.pentacom.jp/itachoco/manual_bento.html'
cssfile = u'./resource/main.css'
db = u'./db/main.sqlite3'

namelist = [u'名前1',
            u'名前2']

locale.setlocale(locale.LC_ALL, '')
form = cgi.FieldStorage()

# functions
def printe(value):
    if isinstance(value, unicode):
        print(value.encode(encode))
    else:
        print(value)

def generate_id(digit=8):
    if not isinstance(digit, int):
        raise TypeError(u'need int, got %r' % \
                        type(digit))
    seed = str(random.randint(0, sys.maxint - 1))
    message = hashlib.new('sha512')
    message.update(seed)
    temp_id = message.hexdigest()
    if len(temp_id) > digit:
        return temp_id[0:digit]
    else:
        return temp_id

# init
con = sqlite3.connect(db)
cur = con.cursor()
cur.execute('select * from sqlite_master \
where type = \'table\' and name = ?;', \
               (u'order_table',))
tablecount = cur.fetchall()
if len(tablecount) == 0:
    cur.execute('create table order_table (id primary key, \
    name, order_no, submenu, order_time, status);')

cur.execute('select * from sqlite_master \
where type = \'table\' and name = ?;', \
               (u'close_table',))
tablecount = cur.fetchall()
if len(tablecount) == 0:
    cur.execute('create table close_table (close_time);')

now = datetime.datetime.now()
sql = 'delete from order_table \
where order_time < datetime(\'{0} 00:00:00\', \'utc\');'.format(now.date())
cur.execute(sql)
result = cur.fetchall()

sql = 'delete from close_table \
where close_time < datetime(\'{0} 00:00:00\', \'utc\');'.format(now.date())
cur.execute(sql)

cur.close()
con.commit()
con.close()


message = u''
mode = form.getvalue(u'mode', u'').decode(u'utf-8').strip()
if mode == u'order':
    name = form.getvalue(u'order_radioname', u'').decode(u'utf-8').strip()
    if name == u'ゲスト':
        name = form.getvalue(u'order_name', u'').decode(u'utf-8').strip()
    if name == u'':
        message += u'<p>名前を入力してください。</p>'

    order_no = form.getvalue(u'order_no', u'').decode(u'utf-8').strip()
    if order_no == u'':
        message += u'<p>弁当を指定してください。</p>'

    submenu = form.getvalue(u'submenu', u'なし').decode(u'utf-8').strip()

    if message == u'':
        id = u''
        while True:
            id = generate_id()

            con = sqlite3.connect(db)
            cur = con.cursor()
            cur.execute('select count(*) from order_table where id = ?;',
                        (id,))
            recordcount = cur.fetchone()
            cur.close()
            con.close()

            if recordcount[0] == 0:
                break
            
        con = sqlite3.connect(db)
        cur = con.cursor()
        cur.execute(u'insert into order_table \
        (id, name, order_no, submenu, order_time, status) \
        values (?, ?, ?, ?, datetime(\'now\'), ?);',
                    (id, name, order_no, submenu, u'ok'))
        cur.close()
        con.commit()
        con.close()
        message = u'<p>{0}さんの注文を追加しました。</p>'.format(name)
elif mode == u'statswitch':
    id = form.getvalue(u'id', u'').decode(u'utf-8').strip()
    status = form.getvalue(u'status', u'').decode(u'utf-8').strip()
    if id != u'' and status != u'':
        if status == u'ok':
            setvalue = u'canceled'
        else:
            setvalue = u'ok'
        con = sqlite3.connect(db)
        cur = con.cursor()
        cur.execute(u'update order_table set status = ? where id = ?;',
                    (setvalue, id))
        cur.close()
        con.commit()
        con.close()
elif mode == u'close_order':
    con = sqlite3.connect(db)
    cur = con.cursor()
    cur.execute(u'insert into close_table \
    (close_time) \
    values (datetime(\'now\'));')
    cur.close()
    con.commit()
    con.close()


con = sqlite3.connect(db)
cur = con.cursor()
cur.execute(u'select min(datetime(close_time, \'localtime\')) \
from close_table;')
closetime = cur.fetchone()[0]
cur.close()
con.close()

if closetime is not None:
    message += u'<p>{0[0]}年{0[1]}月{0[2]}日の注文は {0[3]}時{0[4]}分{0[5]}秒にしめきられました。</p>'.format(
        re.split('[\s\-:]', closetime))

# print http response header
printe(u'''Content-Type: text/html; charset={0}
Pragma: no-cache
Cache-Control: no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT
'''.format(encode))

# print html header
printe(u'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
\t"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>{0}</title>
<link rel="stylesheet" type="text/css" href="{1}" />
</head>'''.format(pagetitle, cssfile))

if closetime is None:
    printe(u'<body>')
else:
    printe(u'<body class="order_closed">')
printe(u'<h1>{0}</h1>'.format(pagetitle))

if message != u'':
    printe(u'<div class="message">{0}</div>'.format(message))

printe(u'''<div id="CLOSE_BUTTON">
<form method="POST">
<input type="hidden" name="mode" value="close_order" />
<p><input type="submit" value="しめきり" /></p>
</form>
</div>''')

con = sqlite3.connect(db)
cur = con.cursor()
cur.execute(u'select id, name, order_no, submenu, datetime(order_time, \'localtime\'), status \
from order_table \
order by order_time desc;')
recs = cur.fetchall()
cur.close()
con.close()

if len(recs) == 0:
    printe(u'<p>注文はありません。</p>')
else:
    printe(u'''<table id="ORDER_TABLE">
<thead>
<tr><th>注文者</th><th>弁当</th><th>サブメニュー</th><th>注文日時</th><th>取消</th></tr>
</thead>
<tbody>''')
    for rec in recs:
        statswitch = u'取消'
        if rec[5] == u'canceled':
            statswitch = u'復帰'
        printe(u'<tr class="{5}"><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td><form method="POST"><input type="hidden" name="mode" value="statswitch" /><input type="hidden" name="id" value="{4}" /><input type="hidden" name="status" value="{5}" /><input type="submit" value="{6}" /></form></td></tr>'.format(
            cgi.escape(rec[1]),
            cgi.escape(rec[2]),
            cgi.escape(rec[3]),
            cgi.escape(rec[4]),
            cgi.escape(rec[0]),
            cgi.escape(rec[5]),
            statswitch))
printe(u'''</tbody>
</table>''')

printe(u'''<form method="POST">
<p><input type="submit" value="最新情報に更新" /></p>
</form>''')


printe(u'''<form method="POST">
<input type="hidden" name="mode" value="order" />
<table id="ORDER_FORM">
<tr><th>注文者名前</th><td>''')
for name in namelist:
    printe(u'''<input type="radio" name="order_radioname" value="{0}" checked="checked" /> {0}'''.format(cgi.escape(name)))
printe(u'''<br /><input type="radio" name="order_radioname" value="ゲスト" checked="checked" /> ゲスト
<input type="text" name="order_name" /></td></tr>
<tr><th>弁当種類</th><td><input type="text" name="order_no" />
<a href="{0}" onclick="window.open(\'{0}\'); return false;">メニュー</a> 
<a href="{1}" onclick="window.open(\'{1}\'); return false;">日替わり</a></td></tr>
<tr><th>サブメニュー</th><td>
<input type="radio" name="submenu" value="お茶" /> お茶
<input type="radio" name="submenu" value="味噌汁" /> 味噌汁
<input type="radio" name="submenu" value="なし"  checked="checked" /> なし
</td></tr>
<tr><td></td><td><input type="submit" /></td></tr>
</table>
</form>'''.format(menuuri, dailyuri))

# html end
printe(u'''</body>
</html>''')
main.css
body {
   background: ivory;
}

.message {
   border: double gold 3px;
   margin: 1em;
   padding: 0.5em
}

.message p {
   margin: 0.5em;
}

table#ORDER_TABLE {
   border: solid silver 2px;
   border-collapse: collapse
}

table#ORDER_TABLE th {
   border: solid silver 1px;
   padding: 4px;
   border-bottom: double silver 3px;
   text-align: center;
   background: bisque;
}

table#ORDER_TABLE td {
   border: solid silver 1px;
   padding: 2px 4px ;
   background: snow;
}

table#ORDER_FORM {
   margin-top: 1em;
}

.canceled {
   text-decoration: line-through;
   color: red;
   font-size: small;
}

div#CLOSE_BUTTON {
   width: 6em;
   float: right;
   text-align: right;
}

div#CLOSE_BUTTON p {
   margin: 0;
}

.order_closed {
   background: gray;
}

.order_closed .message {
   background: #aaa;
   font-weight: bold;
}