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)
 |