
目標
- 全てのテーブル状況を確認できるテンプレートを実装する(日時での抽出)
- 各テーブルの注文状況を確認できるテンプレートを実装する
レジ管理アプリケーションの作成
レジ管理アプリケーションの作成
ここからは、商店スタッフが利用するためのレジ管理アプリケーションを作成していきます。具体的には、全てのテーブル状況を確認できたり、各テーブルの注文状況を確認でき、ユーザー側では行えない注文済みの商品の取り消しや、会計を完了させる機能を実装します。
feature-registerappブランチの作成
Git Bushを立ち上げdevelopブランチから次のコマンドを入力してfeature-registerappブランチを作成して、ブランチの切り替えを行います。
git checkout -b feature-registerappコマンド

プロンプトに(feature-registerapp)と表示されます。レジ管理アプリケーションはこのブランチで作成していきます。
レジ管理アプリケーションに必要なディレクトリとファイルの作成
Visual Studio Codeのエクスプローラーから appsディレクトリ に registerappディレクトリを作成します。
apps/registerappディレクトリに次のディレクトリとファイルを作成します。※作成するファイルについては、名前や中身について、今後変更することものもあります。
- static/css/style.css
- templates/register_base.html
- tamplates/register_orders_status.html
- tamplates/register_bill.html
- tamplates/register_list.html
- app.py
- forms.py
- models.py

レジ管理アプリケーションのプログラミング
この記事では、全てのテーブル状況(伝票)を確認できるテンプレートとロジックを実装します。その時に、ある日時以降の伝票のみを出力できるようにします。この為、伝票の作成時間(created_at)をBillモデルに追加します。
tzdata のインストール
Python の zoneinfo モジュールを使用して”Asia/Tokyo” などの特定のタイムゾーン情報を扱う場合、tzdata が必要となります。
「pip install tzdata」コマンドの利用
(venv) C:\Users\User\Desktop\FlaskProj>pip install tzdata
と入力します。

models.pyの編集(ordersapp内)
ordersapp内のmodels.pyファイルを次のように編集します。
from datetime import timedelta, timezone
from sqlalchemy.sql import func
from apps.common.db import db
JST = timezone(timedelta(hours=9))
# 伝票(Bill)モデル
class Bill(db.Model):
id = db.Column(db.Integer, primary_key=True)
status = db.Column(
db.String(20), default="paid"
) # 伝票のステータス(Order in progress, pending, paid)
table_id = db.Column(
db.Integer, db.ForeignKey("table.id"), nullable=False
) # テーブルとの関連
orders = db.relationship("Order", backref="bill", lazy=True, cascade="all, delete")
table = db.relationship(
"Table", backref="bill_table", uselist=False, overlaps="table,table"
) # 1つのテーブルに1つの伝票
created_at = db.Column(db.DateTime, default=func.now(), server_default=func.now())
def __repr__(self):
return f"<Bill {self.id} - Status: {self.status}>"
def get_created_at_jst(self):
"""JST に変換して取得"""
if self.created_at is None:
return None
return self.created_at.replace(tzinfo=timezone.utc).astimezone(JST)
# 注文(Order)モデル
class Order(db.Model):
id = db.Column(db.Integer, primary_key=True)
table_id = db.Column(db.Integer, db.ForeignKey("table.id"), nullable=False)
bill_id = db.Column(db.Integer, db.ForeignKey("bill.id"), nullable=True)
product_id = db.Column(db.Integer, db.ForeignKey("product.id"), nullable=False)
product_name = db.Column(db.String(100), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
total = db.Column(db.Float, nullable=False) # Float に変更
table = db.relationship("Table", backref="orders", lazy=True)
product = db.relationship("Product", backref="orders", lazy=True)
def __repr__(self):
return f"<Order {self.id} - Table {self.table_id} - {self.product_name} x {self.quantity}>"
created_at = db.Column(db.DateTime, default=func.now(), server_default=func.now())
SQLAlchemy を使ったデータベースのカラム定義しています。
db.DateTime:日時型のカラムです。
server_default=func.now(): データベース側で、レコードが作成された時点の CURRENT_TIMESTAMP(現在時刻)を設定しています。
def get_created_at_jst(self):
"""JST に変換して取得"""
if self.created_at is None:
return None
return self.created_at.replace(tzinfo=timezone.utc).astimezone(JST)
このメソッドは、取得した時間データを日本標準時に変換するためのメソッドです。self.created_at が None の場合、None を返して処理を終了します。
self.created_at.replace(tzinfo=timezone.utc)
created_at は、デフォルトで naive な datetimeであってタイムゾーン情報がありません。ここで、tzinfo=timezone.utc を設定し、明示的に UTC として扱います。
.astimezone(JST)
JST(日本標準時)に変換する。
app.pyの編集(registerapp内)
app.pyファイルを次のように編集します。
import os
from datetime import datetime
from zoneinfo import ZoneInfo
from flask import Blueprint, render_template, request
from apps.ordersapp.models import JST, Bill, Order
register_bp = Blueprint(
"register",
__name__,
template_folder=os.path.join(os.getcwd(), "apps", "registerapp", "templates"),
static_folder=os.path.join(os.getcwd(), "apps", "registerapp", "static"),
)
def create_register_app(app):
"""Blueprintを新規作成し、登録する関数"""
return register_bp
@register_bp.route("/list")
def register_list():
filter_date_str = request.args.get("filter_date") # URLパラメータから日付取得
filter_date = None
if filter_date_str:
filter_date_str = filter_date_str.replace("T", " ")
naive_datetime = datetime.strptime(filter_date_str, "%Y-%m-%d %H:%M")
# 日本時間(JST)を適用
filter_date = naive_datetime.replace(tzinfo=JST)
print(filter_date)
# Bill を基準に取得(作成日で降順ソート)
query = Bill.query
if filter_date:
query = query.filter(Bill.created_at >= filter_date.astimezone(ZoneInfo("UTC")))
bills = query.order_by(Bill.created_at.desc()).all()
# 各 Bill に合計金額を追加
for bill in bills:
bill.total_price = sum(order.total for order in bill.orders)
return render_template("register_list.html", title="伝票一覧", bills=bills)
@register_bp.route("/bill/<int:bill_id>")
def view_bill(bill_id):
bill = Bill.query.get_or_404(bill_id)
print(bill)
# 指定された bill_id に関連する注文を取得
orders = Order.query.filter_by(bill_id=bill.id).all()
# print(orders)
# 合計金額を計算
total_price = sum(order.total for order in orders)
return render_template(
"register_bill.html",
bill=bill,
orders=orders,
total_price=total_price,
title="明細",
)
from datetime import datetime
from zoneinfo import ZoneInfo
datetime: 日時の操作に使用します。
zoneinfo.ZoneInfo: タイムゾーンの管理(JST=日本標準時の指定)を行うものです。
datetime の replace(tzinfo=JST) で JST に変換可能となります。
@register_bp.route("/list")
def register_list():
filter_date_str = request.args.get("filter_date") # URLパラメータから日付取得
filter_date = None
if filter_date_str:
filter_date_str = filter_date_str.replace("T", " ")
naive_datetime = datetime.strptime(filter_date_str, "%Y-%m-%d %H:%M")
# 日本時間(JST)を適用
filter_date = naive_datetime.replace(tzinfo=JST)
print(filter_date)
# Bill を基準に取得(作成日で降順ソート)
query = Bill.query
if filter_date:
query = query.filter(Bill.created_at >= filter_date.astimezone(ZoneInfo("UTC")))
bills = query.order_by(Bill.created_at.desc()).all()
# 各 Bill に合計金額を追加
for bill in bills:
bill.total_price = sum(order.total for order in bill.orders)
return render_template("register_list.html", title="伝票一覧", bills=bills)
このルートは伝票の一覧表を出力するためのものです。
request.args.get(“filter_date”) で URL パラメータ filter_date を取得(例: ?filter_date=2025-03-25T12:00)します。
filter_date_str.replace(“T”, ” “) で “T” を ” ” に変換(ISOフォーマットの整形)します。この “T” は、例えば、日付 (2025-03-25) と時刻 (12:00) を区切るとき、「2025-03-25T12:00」のように使われる文字です。
datetime.strptime(filter_date_str, “%Y-%m-%d %H:%M”) で datetime オブジェクトに変換します。
filter_date.replace(tzinfo=JST) で JST(日本標準時)を適用します。
Bill.query から伝票データを取得し、filter_date 以降のデータのみを取得(UTC 変換して比較)します。
bills = query.order_by(Bill.created_at.desc()).all() で作成日の降順に並び替えます。
bill.total_price = sum(order.total for order in bill.orders) で各伝票の合計金額を計算します。
@register_bp.route("/bill/<int:bill_id>")
def view_bill(bill_id):
bill = Bill.query.get_or_404(bill_id)
print(bill)
# 指定された bill_id に関連する注文を取得
orders = Order.query.filter_by(bill_id=bill.id).all()
# print(orders)
# 合計金額を計算
total_price = sum(order.total for order in orders)
return render_template(
"register_bill.html",
bill=bill,
orders=orders,
total_price=total_price,
title="明細",
)
このルートは、伝票の詳細を出力するものです。
bill_id を受け取り、該当の伝票 (Bill) を取得します。
Bill.query.get_or_404(bill_id) で存在しない場合は 404 エラーを返します。
Order.query.filter_by(bill_id=bill.id).all() で該当の伝票に紐づく注文 (Order) を取得します。
sum(order.total for order in orders) で合計金額を計算します。
apps.pyの編集(ordersapp内)
ordersapp内のapps.pyファイルを次のように編集します。
import os
from flask import Blueprint, redirect, render_template, request, session, url_for
from apps.common.db import db
from apps.ordersapp.forms import OrderForm
from apps.ordersapp.models import Bill, Order
from apps.productsapp.models import Category, Product
from apps.tablesapp.models import Table
orders_bp = Blueprint(
"orders",
__name__,
template_folder=os.path.join(os.getcwd(), "apps", "ordersapp", "templates"),
static_folder=os.path.join(os.getcwd(), "apps", "ordersapp", "static"),
)
# カートをテーブルIDごとにセッションから取得するヘルパー関数
def get_cart(table_id):
if f"cart_{table_id}" not in session:
session[f"cart_{table_id}"] = []
return session[f"cart_{table_id}"]
def create_orders_app(app):
"""Blueprintを新規作成し、登録する関数"""
return orders_bp
@orders_bp.route("/order/table/<int:table_id>", methods=["GET"])
def order_menu(table_id):
table = Table.query.get_or_404(table_id)
categories = Category.query.all()
products = Product.query.all()
cart = get_cart(table_id)
# 現在のテーブルの注文履歴を取得
orders = Order.query.filter_by(table_id=table.id).all()
# Billが存在しない場合は新規作成
if table.bill is None:
bill = Bill(status="Order in progress", table_id=table.id)
db.session.add(bill)
table.bill = bill # TableにBillを関連付け
db.session.commit()
else:
bill = table.bill # すでに存在するBillを使用
# Billの状態をデバッグ
print(f"Bill: {bill}") # ここでbillを参照
# 合計額を計算する
total_amount = sum(order.total for order in orders)
# Billが正しく作成されているかをデバッグ
print(
f"Created Bill ID: {table.bill.id}, Status: {table.bill.status}"
) # デバッグ用
return render_template(
"order_menu.html",
products=products,
cart=cart,
table=table,
categories=categories,
total_amount=total_amount,
orders=orders, # 注文履歴を渡す
title="メニュー一覧",
)
@orders_bp.route(
"/order/table/<int:table_id>/product/<int:product_id>", methods=["GET", "POST"]
)
def order_form(table_id, product_id):
table = Table.query.get_or_404(table_id)
product = Product.query.get_or_404(product_id)
form = OrderForm()
if form.validate_on_submit():
quantity = form.quantity.data
total = product.price * quantity
# カートに追加(テーブルごとにセッションを使用)
cart = get_cart(table_id)
cart.append(
{
"product_id": product.id,
"product_name": product.name,
"product_image": product.image_url,
"quantity": quantity,
"total": total,
}
)
session.modified = True # セッションを変更したことを通知
return redirect(url_for("orders.order_menu", table_id=table.id))
return render_template(
"order_form.html",
form=form,
product=product,
table=table,
title="注文フォーム",
)
@orders_bp.route("/order/cart/<int:table_id>", methods=["GET", "POST"])
def order_cart(table_id):
table = Table.query.get_or_404(table_id)
cart = get_cart(table_id)
total_amount = sum(item["total"] for item in cart)
# テーブルに関連するBillを取得(Billが存在しない場合、新規作成)
if table.bill is None:
bill = Bill(status="Order in progress", table_id=table.id)
db.session.add(bill)
db.session.commit() # 新規作成したBillをDBに保存
table.bill = bill # TableにBillを関連付け
db.session.commit() # 変更をコミット
else:
bill = table.bill # 既に関連付けられているBillを使用
if request.method == "POST":
# 注文確定処理
for item in cart:
# 注文をデータベースに保存
order = Order(
table_id=table.id,
product_id=item["product_id"],
product_name=item["product_name"],
quantity=item["quantity"],
total=item["total"],
bill_id=bill.id, # Billを注文に紐づけ
)
db.session.add(order)
db.session.commit()
# 注文後、カートをクリア
session[f"cart_{table_id}"] = []
session.modified = True
# 確定後、再度注文情報を表示するためにリダイレクト
return redirect(url_for("orders.order_menu", table_id=table.id))
return render_template(
"order_cart.html",
cart=cart,
total_amount=total_amount,
table=table,
title="注文確認フォーム",
)
@orders_bp.route("/order/cart/<int:table_id>/update/<int:product_id>", methods=["POST"])
def update_quantity(table_id, product_id):
table = Table.query.get_or_404(table_id)
quantity = int(request.form.get("quantity"))
cart = get_cart(table_id)
# 商品情報の取得(商品IDから価格などを取得)
product = Product.query.get_or_404(product_id)
# カート内の商品数量を更新
for item in cart:
if item["product_id"] == product_id:
item["quantity"] = quantity
# 商品ごとの合計金額を再計算
item["total"] = item["quantity"] * product.price
session.modified = True
# 合計金額を再計算
total_amount = sum(item["total"] for item in cart)
return redirect(
url_for(
"orders.order_cart", # 適切なビュー名に変更
table_id=table.id,
cart=cart,
total_amount=total_amount,
title="注文確認フォーム",
)
)
@orders_bp.route("/order/cart/<int:table_id>/remove/<int:product_id>", methods=["POST"])
def remove_item(table_id, product_id):
cart = get_cart(table_id)
# カート内の商品を削除
cart = [item for item in cart if item["product_id"] != product_id]
session[f"cart_{table_id}"] = cart # 更新したカートをセッションに保存
session.modified = True
return redirect(url_for("orders.order_cart", table_id=table_id))
@orders_bp.route("/order/table/<int:table_id>/change_status/<status>", methods=["POST"])
def change_status(table_id, status):
"""
注文のステータスを変更する。
statusは「Order in progress」から「pending」へ切り替え
"""
table = Table.query.get_or_404(table_id)
bill = table.bill # テーブルに紐づく伝票(Bill)を取得
# ステータスが変更可能な場合のみ変更
if bill.status != status:
bill.status = (
"pending" if bill.status == "Order in progress" else "Order in progress"
)
db.session.commit()
return redirect(url_for("orders.order_menu", table_id=table.id))
次のルートを修正しています。
@orders_bp.route("/order/table/<int:table_id>", methods=["GET"])
def order_menu(table_id):
table = Table.query.get_or_404(table_id)
categories = Category.query.all()
products = Product.query.all()
cart = get_cart(table_id)
# 現在のテーブルの注文履歴を取得
orders = Order.query.filter_by(table_id=table.id).all()
# Billが存在しない場合は新規作成
if table.bill is None:
bill = Bill(status="Order in progress", table_id=table.id)
db.session.add(bill)
table.bill = bill # TableにBillを関連付け
db.session.commit()
else:
bill = table.bill # すでに存在するBillを使用
# Billの状態をデバッグ
print(f"Bill: {bill}") # ここでbillを参照
# 合計額を計算する
total_amount = sum(order.total for order in orders)
# Billが正しく作成されているかをデバッグ
print(
f"Created Bill ID: {table.bill.id}, Status: {table.bill.status}"
) # デバッグ用
return render_template(
"order_menu.html",
products=products,
cart=cart,
table=table,
categories=categories,
total_amount=total_amount,
orders=orders, # 注文履歴を渡す
title="メニュー一覧",
)
次は具体的な修正・追記内容です。
# Billが存在しない場合は新規作成
if table.bill is None:
bill = Bill(status="Order in progress", table_id=table.id)
db.session.add(bill)
table.bill = bill # TableにBillを関連付け
db.session.commit()
else:
bill = table.bill # すでに存在するBillを使用
ここでは、db.session.commit()をtable.bill = billの後で行うように変更しています。
また、すでにBillが存在する場合は、そのBillを使用するようにelse節を追加しています。
print(f"Bill: {bill}")
Bill オブジェクトの情報を デバッグ表示。
print(
f"Created Bill ID: {table.bill.id}, Status: {table.bill.status}"
)
伝票の IDとステータス を出力し、正常に作成されているか確認しています。
register_base.htmlの編集(registerapp/templates内)
register_base.html を次のように編集します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
{% block title %}
{% endblock %}
</title>
<link rel="stylesheet" href="{{ url_for('register.static', filename='css/style.css') }}">
</head>
<body>
<header>
{% block header %}
<!-- 個別ページのヘッダーがここに入る -->
{% endblock %}
</header>
<main>
{% block content %}
<!-- 個別ページのコンテンツがここに入る -->
{% endblock %}
</main>
<footer>
<p>© 2025 howahowa store</p>
</footer>
</body>
</html>
register_list.htmlの編集(registerapp/templates内)
register_list.html を次のように編集します。
{% extends 'register_base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<form method="GET" action="{{ url_for('register.register_list') }}" class="filter-form">
<label for="filter_date">日付と時間を選択:</label>
<input type="datetime-local" id="filter_date" name="filter_date" value="{{ request.args.get('filter_date', '') }}">
<button type="submit">フィルタ</button>
</form>
<div>
<h2>Pending</h2>
<table>
<thead>
<tr>
<th>伝票番号</th>
<th>テーブル番号</th>
<th>作成日時</th>
<th>合計金額</th>
<th>ステータス</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
{% for bill in bills %}
{% if bill.status == 'pending' %}
<tr>
<td>{{ bill.id }}</td>
<td>{{ bill.table_id }}</td>
<td>{{ bill.get_created_at_jst().strftime('%Y-%m-%d %H:%M') if bill.get_created_at_jst() else '' }}</td>
<td>{{ bill.total_price | int }}</td>
<td>会計予定</td>
<td class="bill-detail"><a href="{{ url_for('register.view_bill', bill_id=bill.id) }}"
class="button-link">詳細</a></td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<div>
<h2>Order in Progress</h2>
<table>
<thead>
<tr>
<th>伝票番号</th>
<th>テーブル番号</th>
<th>作成日時</th>
<th>合計金額</th>
<th>ステータス</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
{% for bill in bills %}
{% if bill.status == 'Order in progress' %}
<tr>
<td>{{ bill.id }}</td>
<td>{{ bill.table_id }}</td>
<td>{{ bill.get_created_at_jst().strftime('%Y-%m-%d %H:%M') if bill.get_created_at_jst() else '' }}</td>
<td>{{ bill.total_price | int }}</td>
<td>注文中</td>
<td class="bill-detail"><a href="{{ url_for('register.view_bill', bill_id=bill.id) }}"
class="button-link">詳細</a></td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<div>
<h2>Paid</h2>
<table>
<thead>
<tr>
<th>伝票番号</th>
<th>テーブル番号</th>
<th>作成日時</th>
<th>合計金額</th>
<th>ステータス</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
{% for bill in bills %}
{% if bill.status == 'paid' %}
<tr>
<td>{{ bill.id }}</td>
<td>{{ bill.table_id }}</td>
<td>{{ bill.get_created_at_jst().strftime('%Y-%m-%d %H:%M') if bill.get_created_at_jst() else '' }}</td>
<td>{{ bill.total_price | int }}</td>
<td>会計済み</td>
<td class="bill-detail"><a href="{{ url_for('register.view_bill', bill_id=bill.id) }}"
class="button-link">詳細</a></td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
register_bill.htmlの編集(registerapp/templates内)
register_bill.html を次のように編集します。
{% extends 'register_base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h1>伝票詳細</h1>
<p>伝票番号: {{ bill.id }}</p>
<p>テーブル番号: {{ bill.table_id }}</p>
<p>作成日時: {{ bill.get_created_at_jst().strftime('%Y-%m-%d %H:%M') if bill.get_created_at_jst() else '' }}</p>
<p style="font-size:xx-large;">合計金額: {{ total_price | int }}</p>
<h2>注文内容</h2>
<table>
<thead>
<tr>
<th>商品名</th>
<th>数量</th>
<th>金額</th>
</tr>
</thead>
<tbody>
{% for order in orders %}
<tr>
<td>{{ order.product_name }}</td>
<td>{{ order.quantity }}</td>
<td>{{ order.total | int }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ url_for('register.register_list') }}" class="button-link-back">戻る</a>
{% endblock %}
style.cssの編集(ordersapp/static/css内)
style.cssを次のように編集します。
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 20px;
background-color: #f8f8f8;
}
header {
margin: 0;
padding: 10px 0;
}
main {
margin: 0;
padding: 20px;
}
footer {
background-color: #aaa;
color: white;
text-align: center;
padding: 10px 0;
margin-top: 20px;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 30px;
text-align: center;
}
h2 {
margin-top: 30px;
font-size: 20px;
font-weight: bold;
color: #333;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th,
td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
th {
background-color: #4CAF50;
color: white;
}
td {
background-color: #fff;
}
tr:hover {
background-color: #f1f1f1;
}
a.button-link {
display: inline-block;
padding: 8px 16px;
background-color: #2196F3;
color: white;
text-align: center;
text-decoration: none;
border-radius: 5px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s ease;
width: 100px;
/* 幅を統一 */
text-align: center;
}
a.button-link:hover {
background-color: #1976D2;
}
a.button-link-back {
display: inline-block;
margin-top: 10px;
padding: 8px 16px;
background-color: #f32121;
color: white;
text-align: center;
text-decoration: none;
border-radius: 5px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s ease;
width: 100px;
/* 幅を統一 */
text-align: center;
}
a.button-link-back:hover {
background-color: #d21919;
}
tr td a.button-link {
display: inline-block;
margin: 0;
}
table td {
word-wrap: break-word;
}
.filter-form {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 8px;
background-color: #f9f9f9;
}
.filter-form label {
font-weight: bold;
color: #333;
}
.filter-form input {
padding: 8px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 4px;
}
.filter-form button {
padding: 8px 15px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.filter-form button:hover {
background-color: #0056b3;
}
.bill-detail {
text-align: center;
padding: 0;
}
order_menu.htmlの編集(ordersapp/templates内)
現状の「order_menu.html」を表示しています。
{% extends 'order_base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2>メニュー</h2>
<!-- カテゴリータブ -->
<div class="tab-container">
<div class="tab active" data-category="all">すべて</div>
{% for category in categories %}
<div class="tab" data-category="{{ category.id }}">{{ category.name }}</div>
{% endfor %}
</div>
<div class="content-container">
<!-- メニューリスト -->
<div class="menu">
{% for product in products %}
{% if product.status != 'discontinued' %}
<div class="menu-item" data-category="{{ product.category_id }}" {% if product.status=='sold_out' or
product.status=='out_of_stock' or table.bill.status=="pending" %}
style="pointer-events: none; opacity: 0.5;" {% endif %}>
<a href="{{ url_for('orders.order_form', table_id=table.id, product_id=product.id) }}" target="_self">
<img src="{{ url_for('products.static', filename=product.image_url) }}" alt="{{ product.name }}">
<p>{{ product.name }}</p>
<p>¥{{ product.price }}</p>
{% if product.status == 'sold_out' %}
<span class="status-label sold-out-label">完売</span>
{% elif product.status == 'out_of_stock' %}
<span class="status-label out-of-stock-label">在庫切れ</span>
{% endif %}
</a>
</div>
{% endif %}
{% endfor %}
</div>
<!-- 注文リスト(右側に配置) -->
<div class="order-summary">
<!-- 合計金額 -->
<div class="total-amount-container">
<p><strong>合計金額: ¥{{ total_amount | int }}</strong></p>
</div>
<div class="cart-check-container">
<!-- カート確認ページへのリンク -->
<a href="{{ url_for('orders.order_cart', table_id=table.id) }}">カートを確認</a>
</div>
<!-- 現在の注文リスト -->
<div class="order-list-container">
<h3>現在の注文リスト</h3>
<ul class="order-list">
{% for order in orders %}
<li>{{ order.product_name }} x{{ order.quantity }} (¥{{ order.total | int }})</li>
{% else %}
<li>現在、注文はありません。</li>
{% endfor %}
</ul>
</div>
<!-- ステータス変更ボタン -->
<div class="status-change-container">
{% if table.bill.status == "Order in progress" %}
<form action="{{ url_for('orders.change_status', table_id=table.id, status='pending') }}" method="post">
<button type="submit" class="status-button">会計予定に変更</button>
</form>
{% elif table.bill.status == "pending" %}
<form action="{{ url_for('orders.change_status', table_id=table.id, status='Order in progress') }}"
method="post">
<button type="submit" class="status-button">注文可能に戻す</button>
</form>
{% endif %}
</div>
</div>
</div>
<!-- カテゴリータブの切り替えスクリプト -->
<script>
document.addEventListener("DOMContentLoaded", function () {
const tabs = document.querySelectorAll(".tab");
const items = document.querySelectorAll(".menu-item");
tabs.forEach(tab => {
tab.addEventListener("click", function () {
const category = this.getAttribute("data-category");
// タブのアクティブ状態を更新
tabs.forEach(t => t.classList.remove("active"));
this.classList.add("active");
// メニューアイテムの表示切り替え
items.forEach(item => {
if (category === "all" || item.getAttribute("data-category") === category) {
item.style.display = "block";
} else {
item.style.display = "none";
}
});
});
});
});
</script>
{% endblock %}
古いデータベースを削除し、アプリケーションを起動します。アプリケーションを起動したら、カテゴリー、商品、テーブルのデータを入力し、いくつかのテーブルで注文を済ませます。
「http://127.0.0.1:5000/register/list」にアクセスします。

いずれかの詳細ボタンをクリックします。次のように詳細情報が表示されます。

ここで、一旦、Gitをコミットしておきます。コミットメッセージは次の通りです。
Add: 伝票一覧の表示機能(20250326)
Add: 伝票の詳細情報を表示する機能(20250326)
今回は設計書などはないため、設計書番号などの提示はなし。レジ管理アプリケーションの実装を開始しています。レジ係が利用する伝票一覧と伝票の詳細情報を確認できるテンプレートとロジックを実装。
git status コマンド

git add . コマンド

git status コマンド

git commit –no-verify コマンド(noの前のハイフンはふたつあります。)

上書き保存をしてCOMMIT_EDITMSGを閉じます。
今回は以上になります。

ブックマークのすすめ
「ほわほわぶろぐ」を常に検索するのが面倒だという方はブックマークをお勧めします。ブックマークの設定は別記事にて掲載しています。

