341 lines
11 KiB
Python
341 lines
11 KiB
Python
"""
|
|
订单视图
|
|
"""
|
|
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/<int:order_id>')
|
|
@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/<int:order_id>', 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/<int:order_id>', 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/<payment_sn>')
|
|
@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)
|