162 lines
5.8 KiB
Python
162 lines
5.8 KiB
Python
# 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.user import db
|
|
from app.utils.auth import admin_required
|
|
from datetime import datetime
|
|
|
|
inventory_bp = Blueprint('inventory', __name__, url_prefix='/inventory')
|
|
|
|
|
|
@inventory_bp.route('/')
|
|
@login_required
|
|
@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
|
|
|
|
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
|
|
@admin_required
|
|
def adjust_inventory(book_id):
|
|
"""调整图书库存"""
|
|
book = Book.query.get_or_404(book_id)
|
|
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
@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
|
|
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
|
|
@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)
|
|
|
|
return render_template('inventory/book_logs.html',
|
|
book=book,
|
|
logs=logs.items,
|
|
pagination=logs)
|