WJUCHU:受注入力[WEB解説]
最終更新:
2025-11-24
#*********************************************************#
#*
#* プログラム名 : WJUCHU.PY
#* タイプ : PYTHON
#* APP タイプ : WDENPYO (WEB 伝票形式テンプレート )
#* 作成日 : 2025/11/06 20:18:38
#* 作成者 : QTR
#* ディレクトリー : /PYTHON.400/PROJECT
#* 使用ファイル : QTRFIL/JUCHU
#* QTRFIL/TANTO
#* QTRFIL/TOKMAS
#* QTRFIL/SHOHIN
#* 監査報告書 : Y
#* 数値の編集 : Y
#* 画面サイズ
#* 桁 : 132
#* 行 : 27
#*
#*********************************************************
import sys
import os
import re
import ibm_db2
import bottle2
import urllib.parse
dspmod = sys.argv[1]
SFLPAG = 10 # 一度の通信でクライアントに返すレコード数
add_count = 0
chg_count = 0
dlt_count = 0
#*************************************************************#
@bottle2.route('/init', method=["GET", "POST"])
def init():
#*************************************************************#
# 初期画面の HTML を表示する。
# パラメータを受け取る
params = bottle2.request.params.decode()
# パラメータがあれば初期画面の HTML にセットする。
values = [{
'JUCNO': params.get('JUCNO', ''),
}]
return bottle2.template('DSPHEAD.HTM', {
'dspmod': dspmod,
'values': values,
'msg': params.get('MSG', ''),
})
#*************************************************************#
@bottle2.route('/input', method=["GET", "POST"])
def input():
#*************************************************************#
# ブラウザからの入力値を受け取る。
params = bottle2.request.params.decode()
# 明細画面の HTM を表示する。
return bottle2.template('DENPYO.HTM', {
'dspmod': 'INPPTN',
'values': [{}],
})
#*************************************************************#
# 明細画面
@bottle2.route('/query', method=["GET"])
def query():
#*************************************************************#
# 明細画面を表示する。
# DB2 に接続する。
with ibm_db2.connected() as conn:
# ブラウザからの入力値を受け取る。
params = bottle2.request.params.decode()
# ヘッダー/フッター情報を取得するための SQL を組み立てる。
sql = '''
SELECT T01.JUCNO
,T01.JUKBN
,T01.JUSHOR
,T01.JUTANT
,T02.TTNAM
,T01.JUTKCD
,T03.TKNM
,T01.JUDATE
,T01.JUNOKI
,T01.JUGYO
,T01.JHCODE
,T04.SHNAME
,T01.JUSUR
,T01.JUTANK
,T01.JUKING
,T01.TTLKNG
FROM QTRFIL/JUCHU T01
LEFT JOIN QTRFIL/TANTO T02
ON T01.JUTANT = T02.TACODE
LEFT JOIN QTRFIL/TOKMAS T03
ON T01.JUTKCD = T03.TKCODE
LEFT JOIN QTRFIL/SHOHIN T04
ON T01.JHCODE = T04.SHCODE
WHERE T01.JUCNO = ?
ORDER BY T01.JUCNO ,
T01.JUGYO
FETCH NEXT 1 ROW ONLY
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする。
# SQL を実行する。
ibm_db2.execute(stmt)
# 結果のレコードを取得する。
values = []
row = ibm_db2.fetch_assoc(stmt)
while row != False:
row['TTLKNG'].edit('1')
row['JUDATE'].edit('W')
row['JUNOKI'].edit('W')
row['JUTANK'].edit('1')
row['JUKING'].edit('1')
values.append(row)
row = ibm_db2.fetch_assoc(stmt)
# レコードが存在しない場合
if len(values) == 0:
if dspmod == 'DSPPTN':
# DSPPTN の場合は初期画面に戻ってメッセージを表示する。
values = [{
'JUCNO': params.get('JUCNO', ''),
}]
return bottle2.template('DSPHEAD.HTM', {
'dspmod': dspmod,
'values': values,
'msg': ' レコードが見つかりません ',
})
else:
# CHGPTN の場合は入力画面を表示する。
values = [{
'JUCNO': params.get('JUCNO', ''),
}]
return bottle2.template('DENPYO.HTM', {
'dspmod': 'INPPTN',
'values': values,
})
return bottle2.template('DENPYO.HTM', {
'dspmod': dspmod,
'values': values,
})
#*************************************************************#
@bottle2.route('/template', method=["GET", "POST"])
def template():
#*************************************************************#
# 入力画面用の空っぽのレコードをブラウザに返す。
return bottle2.template('LISTDEF.HTM', {
'dspmod': 'WRTPTN',
'value': {},
})
#*************************************************************#
@bottle2.route('/record', method=["GET", "POST"])
def record():
#*************************************************************#
# SQL で明細レコードを読み取ってブラウザに返す。
# DB2 に接続する。
with ibm_db2.connected() as conn:
# ブラウザからの入力値を受け取る。
params = bottle2.request.params.decode()
# SQL を組み立てる。
sql = '''
SELECT T01.JUCNO
,T01.JUKBN
,T01.JUSHOR
,T01.JUTANT
,T02.TTNAM
,T01.JUTKCD
,T03.TKNM
,T01.JUDATE
,T01.JUNOKI
,T01.JUGYO
,T01.JHCODE
,T04.SHNAME
,T01.JUSUR
,T01.JUTANK
,T01.JUKING
,T01.TTLKNG
FROM QTRFIL/JUCHU T01
LEFT JOIN QTRFIL/TANTO T02
ON T01.JUTANT = T02.TACODE
LEFT JOIN QTRFIL/TOKMAS T03
ON T01.JUTKCD = T03.TKCODE
LEFT JOIN QTRFIL/SHOHIN T04
ON T01.JHCODE = T04.SHCODE
WHERE T01.JUCNO = ?
ORDER BY T01.JUCNO ,
T01.JUGYO
OFFSET ? ROWS
OFFSET ? ROWS
FETCH NEXT ? ROWS ONLY
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする。
ibm_db2.bind_param(stmt, 2, params['_RRN']) # RRN を SQL にセットする。
ibm_db2.bind_param(stmt, 3, SFLPAG) # SFLPAG を SQL にセットする。
# SQL を実行する。
ibm_db2.execute(stmt)
# 結果のレコードを取得する。
values = []
row = ibm_db2.fetch_assoc(stmt)
while row != False:
row['TTLKNG'].edit('1')
row['JUDATE'].edit('W')
row['JUNOKI'].edit('W')
row['JUNOKI'].edit('W')
row['JUTANK'].edit('1')
row['JUKING'].edit('1')
values.append(row)
row = ibm_db2.fetch_assoc(stmt)
# 結果をテンプレートに埋め込む。
text = ""
for value in values:
text += bottle2.template('LISTDEF.HTM', {
'dspmod': dspmod,
'value': value,
})
# 明細画面の HTM を表示する。
bottle2.response.content_type = 'text/plain';
return text
#*************************************************************#
@bottle2.route('/insert', method=["POST"]) # 伝票の挿入処理
def insert():
#*************************************************************#
# DB2 に接続する。
with ibm_db2.connected() as conn:
# ブラウザからの入力値を受け取る。
params = bottle2.request.forms.decode()
global add_count
txn_add_count = 0;
# ヘッダー/フッターに含まれる数値フィールドについて文字列から数値に変換する
params['TTLKNG'] = int(re.sub(r'[^0-9.+-]', '', params['TTLKNG']))
params['JUCNO'] = int(re.sub(r'[^0-9.+-]', '', params['JUCNO']))
params['JUDATE'] = int(re.sub(r'[^0-9.+-]', '', params['JUDATE']))
params['JUNOKI'] = int(re.sub(r'[^0-9.+-]', '', params['JUNOKI']))
# 明細を挿入する。
for i in range(len(params.getlist('JUGYO'))):
# 空行はスキップ
if params.getall('JUGYO')[i] == '':
continue
# 明細に含まれる数値フィールドについて文字列から数値に変換する。
params.getlist('JUGYO')[i]=int(re.sub(r'[^0-9.-]','',params.getlist('JUGYO')[i]))
params.getlist('JUSUR')[i]=int(re.sub(r'[^0-9.-]','',params.getlist('JUSUR')[i]))
params.getlist('JUTANK')[i]=int(re.sub(r'[^0-9.-]','',params.getlist('JUTANK')[i]))
params.getlist('JUKING')[i]=int(re.sub(r'[^0-9.-]','',params.getlist('JUKING')[i]))
# SQL を組み立てる。
if params.getall('_DSPMOD')[i] == 'WRTPTN':
# レコードの挿入
sql = '''
INSERT QTRFIL/JUCHU
(JUCNO
,JUGYO
,JUKBN
,JUSHOR
,JUTANT
,JUTKCD
,JUDATE
,JUNOKI
,JHCODE
,JUSUR
,JUTANK
,JUKING
,TTLKNG)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする
ibm_db2.bind_param(stmt, 2, params['JUGYO']) # JUGYO を SQL にセットする
ibm_db2.bind_param(stmt, 3, params['JUKBN']) # JUKBN を SQL にセットする
ibm_db2.bind_param(stmt, 4, params['JUSHOR']) # JUSHOR を SQL にセットする
ibm_db2.bind_param(stmt, 5, params['JUTANT']) # JUTANT を SQL にセットする
ibm_db2.bind_param(stmt, 6, params['JUTKCD']) # JUTKCD を SQL にセットする
ibm_db2.bind_param(stmt, 7, params['JUDATE']) # JUDATE を SQL にセットする
ibm_db2.bind_param(stmt, 8, params['JUNOKI']) # JUNOKI を SQL にセットする
ibm_db2.bind_param(stmt, 9, params['JHCODE']) # JHCODE を SQL にセットする
ibm_db2.bind_param(stmt, 10, params['JUSUR']) # JUSUR を SQL にセットする
ibm_db2.bind_param(stmt, 11, params['JUTANK']) # JUTANK を SQL にセットする
ibm_db2.bind_param(stmt, 12, params['JUKING']) # JUKING を SQL にセットする
ibm_db2.bind_param(stmt, 13, params['TTLKNG']) # TTLKNG を SQL にセットする
# SQL を実行する。
ibm_db2.execute(stmt)
txn_add_count += 1;
add_count += 1;
# 初期画面に戻る
msg = "{} レコード追加しました。 ".format(txn_add_count);
return bottle2.redirect('/init?' + urllib.parse.urlencode({
'MSG': msg,
'JUCNO': params['JUCNO'],
}))
#*************************************************************#
@bottle2.route('/update', method=["POST"]) # 更新処理
def update():
#*************************************************************#
# DB2 に接続する。
with ibm_db2.connected() as conn:
# ブラウザからの入力値を受け取る。
params = bottle2.request.forms.decode()
global add_count
global chg_count
txn_chg_count = 0;
txn_add_count = 0;
# ヘッダー/フッターに含まれる数値フィールドについて文字列から数値に変換する
params['TTLKNG'] = int(re.sub(r'[^0-9.+-]', '', params['TTLKNG']))
params['JUCNO'] = int(re.sub(r'[^0-9.+-]', '', params['JUCNO']))
params['JUDATE'] = int(re.sub(r'[^0-9.+-]', '', params['JUDATE']))
params['JUNOKI'] = int(re.sub(r'[^0-9.+-]', '', params['JUNOKI']))
if params['_CHG'] == '*YES':
# ヘッダーまたはフッターに含まれるフィールドが更新された。
# 全ての明細を更新する。
# SQL を組み立てる。
sql = '''
UPDATE QTRFIL/JUCHU
SET JUKBN = ?
,JUSHOR = ?
,JUTANT = ?
,JUTKCD = ?
,JUDATE = ?
,JUNOKI = ?
,TTLKNG = ?
WHERE JUCNO = ?
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUKBN']) # JUKBN を SQL にセットする
ibm_db2.bind_param(stmt, 2, params['JUSHOR']) # JUSHOR を SQL にセットする
ibm_db2.bind_param(stmt, 3, params['JUTANT']) # JUTANT を SQL にセットする
ibm_db2.bind_param(stmt, 4, params['JUTKCD']) # JUTKCD を SQL にセットする
ibm_db2.bind_param(stmt, 5, params['JUDATE']) # JUDATE を SQL にセットする
ibm_db2.bind_param(stmt, 6, params['JUNOKI']) # JUNOKI を SQL にセットする
ibm_db2.bind_param(stmt, 7, params['TTLKNG']) # TTLKNG を SQL にセットする
ibm_db2.bind_param(stmt, 8, params['JUCNO']) # JUCNO を SQL にセットする
# SQL を実行する。
ibm_db2.execute(stmt)
txn_chg_count += ibm_db2.num_rows(stmt);
chg_count += ibm_db2.num_rows(stmt);
# 変更のあった明細を更新する。
for i in range(len(params.getlist('JUGYO'))):
# 空行はスキップ
if params.getall('JUGYO')[i] == '':
continue
# 明細に含まれる数値フィールドについて文字列から数値に変換する。
params.getlist('JUGYO')[i]=int(re.sub(r'[^0-9.+-]','',params.getlist('JUGYO')[i]))
params.getlist('JUSUR')[i]=int(re.sub(r'[^0-9.+-]','',params.getlist('JUSUR')[i]))
params.getlist('JUTANK')[i]=int(re.sub(r'[^0-9.+-]','',params.getlist('JUTANK')[i]))
params.getlist('JUKING')[i]=int(re.sub(r'[^0-9.+-]','',params.getlist('JUKING')[i]))
# SQL を組み立てる。
if params.getall('_DSPMOD')[i] == 'WRTPTN':
# レコードの挿入
sql = '''
INSERT QTRFIL/JUCHU
(JUCNO
,JUGYO
,JUKBN
,JUSHOR
,JUTANT
,JUTKCD
,JUDATE
,JUNOKI
,JHCODE
,JUSUR
,JUTANK
,JUKING
,TTLKNG)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする
ibm_db2.bind_param(stmt, 2, params['JUGYO']) # JUGYO を SQL にセットする
ibm_db2.bind_param(stmt, 3, params['JUKBN']) # JUKBN を SQL にセットする
ibm_db2.bind_param(stmt, 4, params['JUSHOR']) # JUSHOR を SQL にセットする
ibm_db2.bind_param(stmt, 5, params['JUTANT']) # JUTANT を SQL にセットする
ibm_db2.bind_param(stmt, 6, params['JUTKCD']) # JUTKCD を SQL にセットする
ibm_db2.bind_param(stmt, 7, params['JUDATE']) # JUDATE を SQL にセットする
ibm_db2.bind_param(stmt, 8, params['JUNOKI']) # JUNOKI を SQL にセットする
ibm_db2.bind_param(stmt, 9, params['JHCODE']) # JHCODE を SQL にセットする
ibm_db2.bind_param(stmt, 10, params['JUSUR']) # JUSUR を SQL にセットする
ibm_db2.bind_param(stmt, 11, params['JUTANK']) # JUTANK を SQL にセットする
ibm_db2.bind_param(stmt, 12, params['JUKING']) # JUKING を SQL にセットする
ibm_db2.bind_param(stmt, 13, params['TTLKNG']) # TTLKNG を SQL にセットする
# SQL を実行する。
ibm_db2.execute(stmt)
txn_add_count += 1;
add_count += 1;
else:
sql = '''
UPDATE QTRFIL/JUCHU
SET JUGYO =?
,JHCODE =?
,SHNAME =?
,JUSUR =?
,JUTANK =?
,JUKING =?
WHERE JUCNO =?
AND JUGYO =?
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 13, params.getlist('JUGYO')[i]) #JUGYO を SQL にセット
ibm_db2.bind_param(stmt, 14, params.getlist('JHCODE')[i]) #JHCODE を SQL にセット
ibm_db2.bind_param(stmt, 15, params.getlist('SHNAME')[i]) #SHNAME を SQL にセット
ibm_db2.bind_param(stmt, 16, params.getlist('JUSUR')[i]) #JUSUR を SQL にセット
ibm_db2.bind_param(stmt, 17, params.getlist('JUTANK')[i]) #JUTANK を SQL にセット
ibm_db2.bind_param(stmt, 18, params.getlist('JUKING')[i]) #JUKING を SQL にセット
# SQL を実行する。
ibm_db2.execute(stmt)
# ヘッダー/フッターが更新された場合は既にカウントアップ済みのため
# ここではカウントアップしない。
if params['_CHG'] == '*NO':
txn_chg_count += 1
chg_count += 1
# 初期画面に戻る
msgs = []
if txn_add_count > 0:
msgs.append("{} レコード追加 ".format(txn_add_count))
msgs.append("{} レコード更新 ".format(txn_chg_count))
msg = ' 、 '.join(msgs) + " しました。 "
return bottle2.redirect('/init?' + urllib.parse.urlencode({
'MSG': msg,
'JUCNO': params['JUCNO'],
}))
#*************************************************************#
@bottle2.route('/delete', method=["POST"]) # 伝票の削除処理
def delete():
#*************************************************************#
# DB2 に接続する。
with ibm_db2.connected() as conn:
global dlt_count
# ブラウザからの入力値を受け取る。
params = bottle2.request.forms.decode()
txn_dlt_count = 0
# ヘッダー/フッターに含まれる数値フィールドについて文字列から数値に変換する。
params['JUCNO'] = int(re.sub(r'[^0-9.+-]', '', params['JUCNO']))
# 各レコードについて繰り返す。
for i in range(len(params.getall('JUGYO'))):
# チェックが入っていない明細はスキップ
if(params.getall('_CHK')[i] != 'on'):
continue
# SQL を組み立てる。
sql = '''
DELETE FROM QTRFIL/JUCHU
WHERE JUCNO = ?
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする
ibm_db2.bind_param(stmt, 1, params['JUGYO']) # JUGYO を SQL にセットする
# SQL を実行する。
ibm_db2.execute(stmt)
dlt_count += 1
txn_dlt_count += 1
# チェックのついた明細が一つもない場合は伝票全体の削除である。
if txn_dlt_count == 0:
# SQL を組み立てる。
sql = '''
DELETE QTRFIL/JUCHU
WHERE JUCNO = ?
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする
# SQL を実行する。
ibm_db2.execute(stmt)
dlt_count += ibm_db2.num_rows(stmt)
txn_dlt_count += ibm_db2.num_rows(stmt)
# 初期画面に戻る
return bottle2.redirect('/init?' + urllib.parse.urlencode({
'MSG': '{} レコード削除しました '.format(txn_dlt_count),
}))
#*************************************************************#
@bottle2.route('/end', method=["POST"])
def end():
#*************************************************************#
# ブラウザからの入力値を受け取る。
params = bottle2.request.params.decode()
# 終了確認画面の HTML を表示する。
return bottle2.template('ENDOPT.HTM', {
'dspmod': dspmod,
'values': [params],
'add_count': add_count,
'chg_count': chg_count,
'dlt_count': dlt_count,
})
#*************************************************************#
@bottle2.route('/close', method=["POST"])
def close():
#*************************************************************#
# bottle を終了する。
bottle2.shutdown()
#*************************************************************#
@bottle2.route('/icon/')
def icon(path):
#*************************************************************#
return bottle2.static_file(path, '/PYTHON.400/ICON')
#*************************************************************#
# MAIN: 以下のルーチンが最初に実行されるメイン・ルーチンです。
#*************************************************************#
# 使用する HTML テンプレートの場所を宣言する。
HTM_DIR = os.path.dirname(os.path.abspath(__file__))
bottle2.TEMPLATE_PATH[:] = [HTM_DIR]
# HTTP サーバーを起動する。
bottle2.run(host='', port=8080, quiet=True)
[解説]
最初に 関数 initが呼び出されて実行されます。
#*************************************************************#
@bottle2.route('/init', method=["GET", "POST"])
def init():
#*************************************************************#
このinit関数では次のように初期画面 : DSPHEAD.HTM を表示します。
return bottle2.template('DSPHEAD.HTM', {
'dspmod': dspmod,
'values': values,
'msg': params.get('MSG', ''),
})
初期画面 : DSPHEAD.HTM では
<form action="/query" method="get">
<header>
<h1> 受注入力 </h1>
<div class="buttons">
<button type="submit" class="default"><img src="/icon/SEARCH.SVG"> 検索 </button>
にあるように 検索ボタンが押されたら関数: queryを呼び出して実行します。
#*************************************************************#
# 明細画面
@bottle2.route('/query', method=["GET"])
def query():
#*************************************************************#
このquery関数で初期画面で入力された受注№で
受注ファイル(QTRFIL/JUCHU)をSQL文で次のように検索します。
# ヘッダー/フッター情報を取得するための SQL を組み立てる。
sql = '''
SELECT T01.JUCNO
,T01.JUKBN
,T01.JUSHOR
,T01.JUTANT
,T02.TTNAM
,T01.JUTKCD
,T03.TKNM
,T01.JUDATE
,T01.JUNOKI
,T01.JUGYO
,T01.JHCODE
,T04.SHNAME
,T01.JUSUR
,T01.JUTANK
,T01.JUKING
,T01.TTLKNG
FROM QTRFIL/JUCHU T01
LEFT JOIN QTRFIL/TANTO T02
ON T01.JUTANT = T02.TACODE
LEFT JOIN QTRFIL/TOKMAS T03
ON T01.JUTKCD = T03.TKCODE
LEFT JOIN QTRFIL/SHOHIN T04
ON T01.JHCODE = T04.SHCODE
WHERE T01.JUCNO = ?
ORDER BY T01.JUCNO ,
T01.JUGYO
FETCH NEXT 1 ROW ONLY
'''
stmt = ibm_db2.prepare(conn, sql);
ibm_db2.bind_param(stmt, 1, params['JUCNO']) # JUCNO を SQL にセットする。
# SQL を実行する。
ibm_db2.execute(stmt)
結果のレコードを次のように取得して変数valuesに保存します。
# 結果のレコードを取得する。
values = []
row = ibm_db2.fetch_assoc(stmt)
while row != False:
row['TTLKNG'].edit('1')
row['JUDATE'].edit('W')
row['JUNOKI'].edit('W')
row['JUTANK'].edit('1')
row['JUKING'].edit('1')
values.append(row)
row = ibm_db2.fetch_assoc(stmt)
そしてvaluesをHTMLのvaluesに書き込みます。
return bottle2.template('DENPYO.HTM', {
'dspmod': dspmod,
'values': values,
})
HTMLでは各変数はvaluesを使って次のように定義されています。
< class="src">
<span class="value">
<input type="text" name="JHCODE" value="{{value.get('JHCODE', '')}}"
<input type="text" name="JUSUR" value="{{value.get('JUSUR', '')}}"
size="5" maxlength="3" {{"readonly" if dspmod == "DSPPTN" else ""}} style='text-align: right;'>
つまり
value.get('JHCODE', '')
のようにして変数配列 valueの中から値を取り出されて表示されます。
そして明細画面: DENPYO.HTM が次のように表示されます。