update
This commit is contained in:
parent
28922e4cbf
commit
466660d772
@ -13,7 +13,8 @@ from app.models.order import (
|
||||
OrderStatus,
|
||||
OrderCancel,
|
||||
OrderComplete,
|
||||
OrderPriceResult
|
||||
OrderPriceResult,
|
||||
RefundOrderAmountRequest
|
||||
)
|
||||
from app.models.order_additional_fee import OrderAdditionalFeeDB, OrderAdditionalFeeInfo, AdditionalFeeResult
|
||||
from app.models.database import get_db
|
||||
@ -1573,6 +1574,60 @@ async def get_orders(
|
||||
return error_response(code=500, message=f"获取订单列表失败: {str(e)}")
|
||||
|
||||
|
||||
@router.put("/admin/refund_order_amount", response_model=ResponseModel)
|
||||
async def refund_order_amount(
|
||||
request: RefundOrderAmountRequest,
|
||||
db: Session = Depends(get_db),
|
||||
admin_user: UserDB = Depends(get_admin_user)
|
||||
):
|
||||
"""减少订单金额"""
|
||||
try:
|
||||
order = db.query(ShippingOrderDB).filter(ShippingOrderDB.orderid == request.order_id).first()
|
||||
if not order:
|
||||
return error_response(code=404, message="订单不存在")
|
||||
|
||||
# 检查退款金额是否大于订单支付金额
|
||||
if request.amount > order.final_amount:
|
||||
return error_response(code=400, message="退款金额不能大于订单金额")
|
||||
|
||||
order.refund_amount = request.amount
|
||||
order.refund_reason = request.reason
|
||||
order.refund_user_id = admin_user.userid
|
||||
|
||||
order.final_amount -= request.amount
|
||||
|
||||
# 如果订单已经完成,则扣减配送员收益
|
||||
order.delivery_share = calculate_delivery_share(order, db)
|
||||
if order.status == OrderStatus.COMPLETED:
|
||||
# 扣减配送员收益
|
||||
sharing = db.query(CommunityProfitSharing).filter(
|
||||
CommunityProfitSharing.community_id == order.address_community_id
|
||||
).first()
|
||||
if sharing:
|
||||
reduct_share = -round(request.amount * (float(sharing.delivery_rate) / 100.0), 2)
|
||||
manager = AccountManager(db)
|
||||
manager.change_balance(
|
||||
order.deliveryman_user_id,
|
||||
reduct_share,
|
||||
f"配送订单退款",
|
||||
order.orderid
|
||||
)
|
||||
|
||||
wechat = WeChatClient()
|
||||
await wechat.apply_refund(
|
||||
order_id=order.orderid,
|
||||
total_amount=int(float(request.amount) * 100) if not settings.DEBUG else 1, # 转换为分
|
||||
reason="后台退款"
|
||||
)
|
||||
|
||||
db.commit()
|
||||
return success_response(message="减少订单金额成功")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logging.exception(f"减少订单金额失败: {str(e)}")
|
||||
return error_response(code=500, message=f"减少订单金额失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/admin/list", response_model=ResponseModel)
|
||||
async def get_admin_orders(
|
||||
status: Optional[OrderStatus] = None,
|
||||
@ -1654,6 +1709,9 @@ async def get_admin_orders(
|
||||
"complete_images": order.optimized_complete_images,
|
||||
"completed_time": order.completed_time,
|
||||
"final_amount": order.final_amount,
|
||||
"refund_amount": order.refund_amount,
|
||||
"refund_reason": order.refund_reason,
|
||||
"refund_user_id": order.refund_user_id,
|
||||
"packages": package_list,
|
||||
"sub_orders": [PointProductOrderInfo.model_validate(sub_order) for sub_order in sub_orders],
|
||||
"address": {
|
||||
|
||||
@ -26,7 +26,7 @@ import logging
|
||||
from app.core.security import get_password_hash
|
||||
from app.models.order_additional_fee import OrderAdditionalFeeDB, AdditionalFeeResult
|
||||
from app.api.endpoints.order import calculate_delivery_share
|
||||
from app.models.wechat_payment import WechatPaymentRecordDB
|
||||
from app.models.wechat_payment import WechatPaymentRecordDB, WechatRefundRecordDB
|
||||
from app.core.wecombot import WecomBot
|
||||
from app.models.order import OrderInfo
|
||||
|
||||
@ -400,14 +400,52 @@ async def refund_notify(
|
||||
|
||||
# 获取退款信息
|
||||
out_trade_no = data.get("out_trade_no") # 订单号
|
||||
out_refund_no = data.get("out_refund_no") # 退款单号
|
||||
refund_id = data.get("refund_id") # 微信退款单号
|
||||
transaction_id = data.get("transaction_id") # 微信支付交易号
|
||||
status = data.get("refund_status")
|
||||
success_time = data.get("success_time")
|
||||
refund_amount = data.get("amount", {}).get("refund")
|
||||
total_amount = data.get("amount", {}).get("total")
|
||||
user_received_account = data.get("user_received_account")
|
||||
refund_reason = "退款" # 默认退款原因
|
||||
|
||||
# 保存退款记录数据
|
||||
refund_record = WechatRefundRecordDB(
|
||||
out_trade_no=out_trade_no,
|
||||
out_refund_no=out_refund_no,
|
||||
refund_id=refund_id,
|
||||
transaction_id=transaction_id,
|
||||
refund_status=status,
|
||||
success_time=datetime.fromisoformat(success_time.replace('Z', '+00:00')) if success_time else None,
|
||||
refund_amount=float(refund_amount) / 100 if refund_amount else 0,
|
||||
total_amount=float(total_amount) / 100 if total_amount else 0,
|
||||
user_received_account=user_received_account,
|
||||
refund_reason=refund_reason,
|
||||
raw_data=data
|
||||
)
|
||||
db.add(refund_record)
|
||||
|
||||
if not all([out_trade_no, status]) or status != "SUCCESS":
|
||||
return error_response(code=400, message="缺少必要的退款信息或退款未成功")
|
||||
|
||||
# 根据订单类型处理退款
|
||||
if out_trade_no.startswith('M'): # 商家商品订单
|
||||
if out_trade_no.startswith('D'): # 配送订单
|
||||
order = db.query(ShippingOrderDB).filter(
|
||||
ShippingOrderDB.orderid == out_trade_no
|
||||
).first()
|
||||
|
||||
if not order:
|
||||
return error_response(code=404, message="订单不存在或状态不正确")
|
||||
|
||||
# 更新退款相关字段
|
||||
if refund_amount:
|
||||
order.refund_amount = refund_amount
|
||||
|
||||
# 记录退款时间
|
||||
order.refund_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
|
||||
|
||||
elif out_trade_no.startswith('M'): # 商家商品订单
|
||||
order = db.query(MerchantOrderDB).filter(
|
||||
MerchantOrderDB.order_id == out_trade_no,
|
||||
MerchantOrderDB.status == MerchantOrderStatus.REFUNDING
|
||||
@ -418,7 +456,7 @@ async def refund_notify(
|
||||
|
||||
# 更新订单状态
|
||||
order.status = MerchantOrderStatus.CANCELLED
|
||||
order.refund_transaction_id = data.get("transaction_id")
|
||||
order.refund_transaction_id = transaction_id
|
||||
order.refund_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
|
||||
|
||||
elif out_trade_no.startswith('P'): # 商家在线买单
|
||||
|
||||
@ -94,6 +94,12 @@ class ShippingOrderDB(Base):
|
||||
pay_time = Column(DateTime(timezone=True)) # 支付时间
|
||||
transaction_id = Column(String(64)) # 微信支付交易号
|
||||
|
||||
# 退款相关字段
|
||||
refund_amount = Column(Float, default=0) # 退款金额
|
||||
refund_reason = Column(String(200), nullable=True) # 退款原因
|
||||
refund_user_id = Column(Integer, ForeignKey("users.userid"), nullable=True) # 退款操作人
|
||||
refund_time = Column(DateTime(timezone=True), nullable=True) # 退款时间
|
||||
|
||||
@property
|
||||
def optimized_complete_images(self):
|
||||
if self.complete_images:
|
||||
@ -196,11 +202,11 @@ class OrderInfo(BaseModel):
|
||||
completed_time: Optional[datetime] = None
|
||||
is_first_order: bool
|
||||
|
||||
# def __init__(self, **data):
|
||||
# super().__init__(**data)
|
||||
# # 将逗号分隔的图片URL字符串转换为列表
|
||||
# if self.complete_images and isinstance(self.complete_images, str):
|
||||
# self.complete_images = self.complete_images.split(",")
|
||||
# 退款相关字段
|
||||
refund_amount: float = 0
|
||||
refund_reason: Optional[str] = None
|
||||
refund_user_id: Optional[int] = None
|
||||
refund_time: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@ -242,3 +248,8 @@ class OrderPriceResult(BaseModel):
|
||||
used_coupon_id: Optional[int] = None # 使用的优惠券ID
|
||||
used_points: Optional[int] = None # 使用的积分数
|
||||
price_detail_text: Optional[str] = None # 价格详情文本
|
||||
|
||||
class RefundOrderAmountRequest(BaseModel):
|
||||
order_id: str
|
||||
amount: float
|
||||
reason: str
|
||||
@ -48,3 +48,44 @@ class WechatPaymentRecordInfo(BaseModel):
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class WechatRefundRecordDB(Base):
|
||||
"""微信退款记录表"""
|
||||
__tablename__ = "wechat_refund_records"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
out_trade_no = Column(String(32), nullable=False, index=True, comment='商户订单号')
|
||||
out_refund_no = Column(String(64), nullable=False, index=True, comment='商户退款单号')
|
||||
refund_id = Column(String(64), index=True, comment='微信退款单号')
|
||||
transaction_id = Column(String(64), index=True, comment='微信支付交易号')
|
||||
refund_status = Column(String(32), comment='退款状态')
|
||||
success_time = Column(DateTime(timezone=True), comment='退款成功时间')
|
||||
refund_amount = Column(DECIMAL(10, 2), comment='退款金额')
|
||||
total_amount = Column(DECIMAL(10, 2), comment='订单总金额')
|
||||
user_received_account = Column(String(256), comment='退款入账账户')
|
||||
currency = Column(String(16), default='CNY', comment='货币类型')
|
||||
refund_reason = Column(String(256), comment='退款原因')
|
||||
raw_data = Column(JSON, comment='原始返回数据')
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now(), comment='创建时间')
|
||||
update_time = Column(DateTime(timezone=True), onupdate=func.now(), comment='更新时间')
|
||||
|
||||
# Pydantic 模型
|
||||
class WechatRefundRecordInfo(BaseModel):
|
||||
id: int
|
||||
out_trade_no: str
|
||||
out_refund_no: str
|
||||
refund_id: Optional[str] = None
|
||||
transaction_id: Optional[str] = None
|
||||
refund_status: Optional[str] = None
|
||||
success_time: Optional[datetime] = None
|
||||
refund_amount: Optional[float] = None
|
||||
total_amount: Optional[float] = None
|
||||
user_received_account: Optional[str] = None
|
||||
currency: str = 'CNY'
|
||||
refund_reason: Optional[str] = None
|
||||
raw_data: Optional[Dict[str, Any]] = None
|
||||
create_time: datetime
|
||||
update_time: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@ -176,4 +176,13 @@ ADD UNIQUE INDEX uix_fee_order_id (fee_order_id);
|
||||
ALTER TABLE order_additional_fees
|
||||
ADD COLUMN transaction_id VARCHAR(64) NULL COMMENT '微信支付交易号';
|
||||
|
||||
--====FINISH 4.5====
|
||||
|
||||
-- 为 shipping_orders 表添加 refund_amount 等字段
|
||||
ALTER TABLE shipping_orders
|
||||
ADD COLUMN refund_amount FLOAT DEFAULT 0,
|
||||
ADD COLUMN refund_reason VARCHAR(200),
|
||||
ADD COLUMN refund_user_id INT,
|
||||
ADD CONSTRAINT fk_refund_user_id FOREIGN KEY (refund_user_id) REFERENCES users(userid);
|
||||
|
||||
|
||||
|
||||
BIN
jobs.sqlite
BIN
jobs.sqlite
Binary file not shown.
Loading…
Reference in New Issue
Block a user