Book_system/app/controllers/inventory.py
2025-05-14 15:08:06 +08:00

233 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# app/controllers/inventory.py
from flask import Blueprint, render_template, request, jsonify, flash, redirect, url_for
from flask_login import login_required, current_user
from app.models.book import Book
from app.models.inventory import InventoryLog
from app.models.log import Log # 导入日志模型
from app.models.user import db
from app.utils.auth import permission_required # 修改导入使用permission_required替代admin_required
from datetime import datetime
inventory_bp = Blueprint('inventory', __name__, url_prefix='/inventory')
@inventory_bp.route('/')
@login_required
@permission_required('manage_inventory') # 替代 @admin_required
def inventory_list():
"""库存管理页面 - 只有拥有库存管理权限的用户有权限进入"""
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
# 搜索功能
search = request.args.get('search', '')
query = Book.query
if search:
query = query.filter(
(Book.title.contains(search)) |
(Book.author.contains(search)) |
(Book.isbn.contains(search))
)
# 排序
sort = request.args.get('sort', 'id')
order = request.args.get('order', 'asc')
if order == 'desc':
query = query.order_by(getattr(Book, sort).desc())
else:
query = query.order_by(getattr(Book, sort))
pagination = query.paginate(page=page, per_page=per_page)
books = pagination.items
# 记录系统日志 - 访问库存管理页面
Log.add_log(
action="访问库存管理",
user_id=current_user.id,
target_type="inventory",
ip_address=request.remote_addr,
description=f"用户访问库存管理页面,搜索条件:{search if search else ''}"
)
return render_template('inventory/list.html',
books=books,
pagination=pagination,
search=search,
sort=sort,
order=order)
@inventory_bp.route('/adjust/<int:book_id>', methods=['GET', 'POST'])
@login_required
@permission_required('manage_inventory') # 替代 @admin_required
def adjust_inventory(book_id):
"""调整图书库存"""
book = Book.query.get_or_404(book_id)
# GET请求记录日志
if request.method == 'GET':
Log.add_log(
action="查看库存调整",
user_id=current_user.id,
target_type="book",
target_id=book.id,
ip_address=request.remote_addr,
description=f"用户查看图书《{book.title}》的库存调整页面"
)
if request.method == 'POST':
change_type = request.form.get('change_type')
change_amount = int(request.form.get('change_amount', 0))
remark = request.form.get('remark', '')
if change_amount <= 0:
flash('调整数量必须大于0', 'danger')
return redirect(url_for('inventory.adjust_inventory', book_id=book_id))
# 计算库存变化
original_stock = book.stock
if change_type == 'in':
book.stock += change_amount
after_stock = book.stock
operation_desc = "入库"
elif change_type == 'out':
if book.stock < change_amount:
flash('出库数量不能大于当前库存', 'danger')
return redirect(url_for('inventory.adjust_inventory', book_id=book_id))
book.stock -= change_amount
after_stock = book.stock
operation_desc = "出库"
else:
flash('无效的操作类型', 'danger')
return redirect(url_for('inventory.adjust_inventory', book_id=book_id))
# 创建库存日志
log = InventoryLog(
book_id=book.id,
change_type=change_type,
change_amount=change_amount,
after_stock=after_stock,
operator_id=current_user.id,
remark=remark,
changed_at=datetime.now()
)
try:
db.session.add(log)
# 记录系统日志 - 库存调整
Log.add_log(
action=f"库存{operation_desc}",
user_id=current_user.id,
target_type="book",
target_id=book.id,
ip_address=request.remote_addr,
description=f"用户对图书《{book.title}》进行{operation_desc}操作,数量:{change_amount}"
f"原库存:{original_stock},现库存:{after_stock},备注:{remark}"
)
db.session.commit()
flash(f'图书《{book.title}》库存调整成功!原库存:{original_stock},现库存:{after_stock}', 'success')
return redirect(url_for('inventory.inventory_list'))
except Exception as e:
db.session.rollback()
flash(f'操作失败:{str(e)}', 'danger')
return redirect(url_for('inventory.adjust_inventory', book_id=book_id))
return render_template('inventory/adjust.html', book=book)
@inventory_bp.route('/logs')
@login_required
@permission_required('manage_inventory') # 替代 @admin_required
def inventory_logs():
"""查看库存变动日志"""
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
# 搜索和筛选
book_id = request.args.get('book_id', type=int)
change_type = request.args.get('change_type', '')
date_from = request.args.get('date_from', '')
date_to = request.args.get('date_to', '')
query = InventoryLog.query
if book_id:
query = query.filter_by(book_id=book_id)
if change_type:
query = query.filter_by(change_type=change_type)
if date_from:
query = query.filter(InventoryLog.changed_at >= datetime.strptime(date_from, '%Y-%m-%d'))
if date_to:
query = query.filter(InventoryLog.changed_at <= datetime.strptime(date_to + ' 23:59:59', '%Y-%m-%d %H:%M:%S'))
# 默认按时间倒序
query = query.order_by(InventoryLog.changed_at.desc())
pagination = query.paginate(page=page, per_page=per_page)
logs = pagination.items
# 获取所有图书用于筛选
books = Book.query.all()
# 如果特定 book_id 被指定,也获取该书的详细信息
book = Book.query.get(book_id) if book_id else None
# 记录系统日志 - 查看库存日志
filter_desc = []
if book_id:
book_title = book.title if book else f"ID:{book_id}"
filter_desc.append(f"图书:{book_title}")
if change_type:
change_type_text = "入库" if change_type == "in" else "出库"
filter_desc.append(f"操作类型:{change_type_text}")
if date_from or date_to:
date_range = f"{date_from or '无限制'}{date_to or '无限制'}"
filter_desc.append(f"日期范围:{date_range}")
Log.add_log(
action="查看库存日志",
user_id=current_user.id,
target_type="inventory_log",
ip_address=request.remote_addr,
description=f"用户查看库存变动日志,筛选条件:{', '.join(filter_desc) if filter_desc else ''}"
)
return render_template('inventory/logs.html',
logs=logs,
pagination=pagination,
books=books,
book=book,
book_id=book_id,
change_type=change_type,
date_from=date_from,
date_to=date_to)
@inventory_bp.route('/book/<int:book_id>/logs')
@login_required
@permission_required('manage_inventory') # 替代 @admin_required
def book_inventory_logs(book_id):
"""查看特定图书的库存变动日志"""
book = Book.query.get_or_404(book_id)
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
logs = InventoryLog.query.filter_by(book_id=book_id) \
.order_by(InventoryLog.changed_at.desc()) \
.paginate(page=page, per_page=per_page)
# 记录系统日志 - 查看特定图书的库存日志
Log.add_log(
action="查看图书库存日志",
user_id=current_user.id,
target_type="book",
target_id=book.id,
ip_address=request.remote_addr,
description=f"用户查看图书《{book.title}》的库存变动日志"
)
return render_template('inventory/book_logs.html',
book=book,
logs=logs.items,
pagination=logs)