183 lines
6.7 KiB
Python
183 lines
6.7 KiB
Python
"""
|
||
订单模型
|
||
"""
|
||
from datetime import datetime, timedelta
|
||
import json
|
||
from config.database import db
|
||
from app.models.user import User
|
||
from app.models.product import Product
|
||
|
||
|
||
class Order(db.Model):
|
||
"""订单模型"""
|
||
__tablename__ = 'orders'
|
||
|
||
id = db.Column(db.Integer, primary_key=True)
|
||
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||
order_sn = db.Column(db.String(50), unique=True, nullable=False)
|
||
total_amount = db.Column(db.Numeric(10, 2), nullable=False)
|
||
actual_amount = db.Column(db.Numeric(10, 2), nullable=False)
|
||
shipping_fee = db.Column(db.Numeric(10, 2), default=0)
|
||
status = db.Column(db.Integer, default=1) # 1-待支付 2-待发货 3-待收货 4-待评价 5-已完成 6-已取消 7-退款中
|
||
payment_method = db.Column(db.String(20))
|
||
shipping_method = db.Column(db.String(50))
|
||
receiver_info = db.Column(db.Text) # JSON格式存储收货人信息
|
||
remark = db.Column(db.Text)
|
||
shipped_at = db.Column(db.DateTime)
|
||
received_at = db.Column(db.DateTime)
|
||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||
|
||
# 关联关系
|
||
user = db.relationship('User', backref='orders')
|
||
order_items = db.relationship('OrderItem', backref='order', cascade='all, delete-orphan')
|
||
|
||
# 状态常量
|
||
STATUS_PENDING_PAYMENT = 1 # 待支付
|
||
STATUS_PENDING_SHIPMENT = 2 # 待发货
|
||
STATUS_SHIPPED = 3 # 待收货
|
||
STATUS_PENDING_REVIEW = 4 # 待评价
|
||
STATUS_COMPLETED = 5 # 已完成
|
||
STATUS_CANCELLED = 6 # 已取消
|
||
STATUS_REFUNDING = 7 # 退款中
|
||
|
||
STATUS_CHOICES = {
|
||
STATUS_PENDING_PAYMENT: '待支付',
|
||
STATUS_PENDING_SHIPMENT: '待发货',
|
||
STATUS_SHIPPED: '待收货',
|
||
STATUS_PENDING_REVIEW: '待评价',
|
||
STATUS_COMPLETED: '已完成',
|
||
STATUS_CANCELLED: '已取消',
|
||
STATUS_REFUNDING: '退款中'
|
||
}
|
||
|
||
def get_status_text(self):
|
||
"""获取状态文本"""
|
||
return self.STATUS_CHOICES.get(self.status, '未知状态')
|
||
|
||
def get_receiver_info(self):
|
||
"""获取收货人信息"""
|
||
if self.receiver_info:
|
||
try:
|
||
return json.loads(self.receiver_info)
|
||
except:
|
||
return {}
|
||
return {}
|
||
|
||
def set_receiver_info(self, info):
|
||
"""设置收货人信息"""
|
||
if isinstance(info, dict):
|
||
self.receiver_info = json.dumps(info, ensure_ascii=False)
|
||
|
||
def is_expired(self):
|
||
"""检查订单是否已过期(15分钟未支付)"""
|
||
if self.status == self.STATUS_PENDING_PAYMENT:
|
||
expire_time = self.created_at + timedelta(minutes=15)
|
||
return datetime.utcnow() > expire_time
|
||
return False
|
||
|
||
def can_cancel(self):
|
||
"""检查是否可以取消"""
|
||
return self.status in [self.STATUS_PENDING_PAYMENT, self.STATUS_PENDING_SHIPMENT]
|
||
|
||
def can_pay(self):
|
||
"""检查是否可以支付"""
|
||
return self.status == self.STATUS_PENDING_PAYMENT and not self.is_expired()
|
||
|
||
def can_confirm_receipt(self):
|
||
"""检查是否可以确认收货"""
|
||
return self.status == self.STATUS_SHIPPED
|
||
|
||
def to_dict(self):
|
||
"""转换为字典"""
|
||
return {
|
||
'id': self.id,
|
||
'order_sn': self.order_sn,
|
||
'total_amount': float(self.total_amount),
|
||
'actual_amount': float(self.actual_amount),
|
||
'shipping_fee': float(self.shipping_fee),
|
||
'status': self.status,
|
||
'status_text': self.get_status_text(),
|
||
'payment_method': self.payment_method,
|
||
'shipping_method': self.shipping_method,
|
||
'receiver_info': self.get_receiver_info(),
|
||
'remark': self.remark,
|
||
'can_cancel': self.can_cancel(),
|
||
'can_pay': self.can_pay(),
|
||
'can_confirm_receipt': self.can_confirm_receipt(),
|
||
'is_expired': self.is_expired(),
|
||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||
'shipped_at': self.shipped_at.isoformat() if self.shipped_at else None,
|
||
'received_at': self.received_at.isoformat() if self.received_at else None
|
||
}
|
||
|
||
@classmethod
|
||
def generate_order_sn(cls):
|
||
"""生成订单号"""
|
||
import time
|
||
import random
|
||
timestamp = str(int(time.time()))
|
||
random_str = str(random.randint(100000, 999999))
|
||
return f"TB{timestamp}{random_str}"
|
||
|
||
def __repr__(self):
|
||
return f'<Order {self.order_sn}>'
|
||
|
||
|
||
class OrderItem(db.Model):
|
||
"""订单商品明细模型"""
|
||
__tablename__ = 'order_items'
|
||
|
||
id = db.Column(db.Integer, primary_key=True)
|
||
order_id = db.Column(db.Integer, db.ForeignKey('orders.id'), nullable=False)
|
||
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False)
|
||
sku_code = db.Column(db.String(100))
|
||
product_name = db.Column(db.String(200), nullable=False)
|
||
product_image = db.Column(db.String(255))
|
||
spec_combination = db.Column(db.String(255))
|
||
price = db.Column(db.Numeric(10, 2), nullable=False)
|
||
quantity = db.Column(db.Integer, nullable=False)
|
||
total_price = db.Column(db.Numeric(10, 2), nullable=False)
|
||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||
|
||
# 关联关系
|
||
product = db.relationship('Product', backref='order_items')
|
||
|
||
def to_dict(self):
|
||
"""转换为字典"""
|
||
return {
|
||
'id': self.id,
|
||
'product_id': self.product_id,
|
||
'product_name': self.product_name,
|
||
'product_image': self.product_image,
|
||
'spec_combination': self.spec_combination,
|
||
'price': float(self.price),
|
||
'quantity': self.quantity,
|
||
'total_price': float(self.total_price)
|
||
}
|
||
|
||
def __repr__(self):
|
||
return f'<OrderItem {self.product_name}>'
|
||
|
||
|
||
class ShippingInfo(db.Model):
|
||
"""物流信息模型"""
|
||
__tablename__ = 'shipping_info'
|
||
|
||
id = db.Column(db.Integer, primary_key=True)
|
||
order_id = db.Column(db.Integer, db.ForeignKey('orders.id'), nullable=False)
|
||
shipping_company = db.Column(db.String(50))
|
||
tracking_number = db.Column(db.String(100))
|
||
shipping_status = db.Column(db.Integer, default=1) # 1-已发货 2-运输中 3-已送达
|
||
shipping_address = db.Column(db.Text)
|
||
estimated_delivery = db.Column(db.DateTime)
|
||
actual_delivery = db.Column(db.DateTime)
|
||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||
|
||
# 关联关系
|
||
order = db.relationship('Order', backref='shipping_info')
|
||
|
||
def __repr__(self):
|
||
return f'<ShippingInfo {self.tracking_number}>'
|