""" 订单视图 """ from flask import Blueprint, render_template, request, jsonify, session, redirect, url_for, flash, g from app.models.order import Order, OrderItem from app.models.cart import Cart from app.models.address import UserAddress from app.models.product import ProductInventory from app.models.payment import Payment from app.forms import CheckoutForm from app.utils.decorators import login_required from config.database import db import json order_bp = Blueprint('order', __name__, url_prefix='/order') @order_bp.route('/checkout') @login_required def checkout(): """订单结算页面""" user_id = session['user_id'] selected_items = request.args.getlist('items') if not selected_items: flash('请选择要购买的商品', 'error') return redirect(url_for('cart.index')) # 获取选中的购物车项目 cart_items = Cart.query.filter( Cart.id.in_(selected_items), Cart.user_id == user_id ).all() if not cart_items: flash('选中的商品不存在', 'error') return redirect(url_for('cart.index')) # 检查商品可用性和库存 unavailable_items = [] total_amount = 0 for item in cart_items: if not item.is_available(): unavailable_items.append(item.product.name) else: total_amount += item.get_total_price() if unavailable_items: flash(f'以下商品库存不足或已下架:{", ".join(unavailable_items)}', 'error') return redirect(url_for('cart.index')) # 获取用户地址 addresses = UserAddress.get_user_addresses(user_id) if not addresses: flash('请先添加收货地址', 'warning') return redirect(url_for('address.add')) # 计算运费 shipping_fee = 0 # 默认免运费 # 创建表单并设置地址选项 form = CheckoutForm() form.address_id.choices = [(addr.id, f"{addr.receiver_name} - {addr.get_full_address()}") for addr in addresses] # 设置默认地址 default_address = UserAddress.get_default_address(user_id) if default_address: form.address_id.data = default_address.id return render_template('order/checkout.html', cart_items=cart_items, addresses=addresses, form=form, total_amount=total_amount, shipping_fee=shipping_fee, final_amount=total_amount + shipping_fee) @order_bp.route('/create', methods=['POST']) @login_required def create(): """创建订单""" try: user_id = session['user_id'] data = request.get_json() selected_items = data.get('selected_items', []) address_id = data.get('address_id') shipping_method = data.get('shipping_method', 'standard') payment_method = data.get('payment_method', 'wechat') remark = data.get('remark', '') if not selected_items or not address_id: return jsonify({'success': False, 'message': '参数错误'}) # 获取购物车商品 cart_items = Cart.query.filter( Cart.id.in_(selected_items), Cart.user_id == user_id ).all() if not cart_items: return jsonify({'success': False, 'message': '购物车商品不存在'}) # 验证地址 address = UserAddress.query.filter_by(id=address_id, user_id=user_id).first() if not address: return jsonify({'success': False, 'message': '收货地址不存在'}) # 再次检查库存和计算总价 total_amount = 0 order_items_data = [] for cart_item in cart_items: if not cart_item.is_available(): return jsonify({ 'success': False, 'message': f'商品"{cart_item.product.name}"库存不足或已下架' }) # 检查库存是否足够 current_stock = cart_item.get_stock() if current_stock < cart_item.quantity: return jsonify({ 'success': False, 'message': f'商品"{cart_item.product.name}"库存不足,仅剩{current_stock}件' }) item_total = cart_item.get_total_price() total_amount += item_total order_items_data.append({ 'product_id': cart_item.product_id, 'sku_code': cart_item.sku_code, 'product_name': cart_item.product.name, 'product_image': cart_item.product.main_image, 'spec_combination': cart_item.spec_combination, 'price': cart_item.get_price(), 'quantity': cart_item.quantity, 'total_price': item_total }) # 计算运费 shipping_fee_map = { 'standard': 0, 'express': 10, 'same_day': 20 } shipping_fee = shipping_fee_map.get(shipping_method, 0) actual_amount = total_amount + shipping_fee # 创建订单 order = Order( user_id=user_id, order_sn=Order.generate_order_sn(), total_amount=total_amount, actual_amount=actual_amount, shipping_fee=shipping_fee, payment_method=payment_method, shipping_method=shipping_method, remark=remark ) # 设置收货人信息 order.set_receiver_info({ 'receiver_name': address.receiver_name, 'receiver_phone': address.receiver_phone, 'province': address.province, 'city': address.city, 'district': address.district, 'detail_address': address.detail_address, 'postal_code': address.postal_code, 'full_address': address.get_full_address() }) db.session.add(order) db.session.flush() # 获取订单ID # 创建订单商品明细 for item_data in order_items_data: order_item = OrderItem( order_id=order.id, **item_data ) db.session.add(order_item) # 扣减库存 for cart_item in cart_items: if cart_item.sku_code: sku_info = ProductInventory.query.filter_by(sku_code=cart_item.sku_code).first() if sku_info: sku_info.stock -= cart_item.quantity # 增加销量 cart_item.product.sales_count += cart_item.quantity # 删除购物车商品 for cart_item in cart_items: db.session.delete(cart_item) # 创建支付记录 payment = Payment( order_id=order.id, payment_sn=Payment.generate_payment_sn(), payment_method=payment_method, amount=actual_amount ) db.session.add(payment) db.session.commit() return jsonify({ 'success': True, 'message': '订单创建成功', 'order_id': order.id, 'order_sn': order.order_sn, 'payment_sn': payment.payment_sn }) except Exception as e: db.session.rollback() return jsonify({'success': False, 'message': f'创建订单失败: {str(e)}'}) @order_bp.route('/list') @login_required def list(): """订单列表""" user_id = session['user_id'] status = request.args.get('status', type=int) page = request.args.get('page', 1, type=int) per_page = 10 query = Order.query.filter_by(user_id=user_id) if status: query = query.filter_by(status=status) orders = query.order_by(Order.created_at.desc()).paginate( page=page, per_page=per_page, error_out=False ) return render_template('user/orders.html', orders=orders, current_status=status) @order_bp.route('/detail/') @login_required def detail(order_id): """订单详情""" user_id = session['user_id'] order = Order.query.filter_by(id=order_id, user_id=user_id).first_or_404() return render_template('order/detail.html', order=order) @order_bp.route('/cancel/', methods=['POST']) @login_required def cancel(order_id): """取消订单""" try: user_id = session['user_id'] order = Order.query.filter_by(id=order_id, user_id=user_id).first() if not order: return jsonify({'success': False, 'message': '订单不存在'}) if not order.can_cancel(): return jsonify({'success': False, 'message': '订单状态不允许取消'}) # 更新订单状态 order.status = Order.STATUS_CANCELLED # 恢复库存 for item in order.order_items: if item.sku_code: sku_info = ProductInventory.query.filter_by(sku_code=item.sku_code).first() if sku_info: sku_info.stock += item.quantity # 减少销量 if item.product: item.product.sales_count = max(0, item.product.sales_count - item.quantity) db.session.commit() return jsonify({'success': True, 'message': '订单已取消'}) except Exception as e: db.session.rollback() return jsonify({'success': False, 'message': f'取消失败: {str(e)}'}) @order_bp.route('/confirm_receipt/', methods=['POST']) @login_required def confirm_receipt(order_id): """确认收货""" try: user_id = session['user_id'] order = Order.query.filter_by(id=order_id, user_id=user_id).first() if not order: return jsonify({'success': False, 'message': '订单不存在'}) if not order.can_confirm_receipt(): return jsonify({'success': False, 'message': '订单状态不允许确认收货'}) # 更新订单状态 order.status = Order.STATUS_PENDING_REVIEW order.received_at = db.func.now() db.session.commit() return jsonify({'success': True, 'message': '确认收货成功'}) except Exception as e: db.session.rollback() return jsonify({'success': False, 'message': f'确认收货失败: {str(e)}'}) @order_bp.route('/pay/') @login_required def pay(payment_sn): """支付页面""" user_id = session['user_id'] payment = Payment.query.filter_by(payment_sn=payment_sn).first_or_404() order = payment.order # 验证订单所有权 if order.user_id != user_id: flash('订单不存在', 'error') return redirect(url_for('order.list')) # 检查是否可以支付 if not order.can_pay(): flash('订单不可支付', 'error') return redirect(url_for('order.detail', order_id=order.id)) return render_template('order/pay.html', order=order, payment=payment)