修改先享后付

This commit is contained in:
aaron 2025-04-01 11:28:40 +08:00
parent 5ce525693a
commit 9b2cf46403
10 changed files with 158 additions and 42 deletions

View File

@ -175,12 +175,14 @@ async def check_activity_can_receive(
return False, f"优惠券活动已领完", activity return False, f"优惠券活动已领完", activity
# 检查用户领取次数 # 检查用户领取次数
user_receive_count = db.query(func.count(CouponReceiveRecordDB.id)).filter( record = db.query(CouponReceiveRecordDB).filter(
CouponReceiveRecordDB.user_id == current_user.userid, CouponReceiveRecordDB.user_id == current_user.userid,
CouponReceiveRecordDB.activity_id == activity_id CouponReceiveRecordDB.activity_id == activity_id
).scalar() ).first()
if user_receive_count >= activity.user_limit:
return False, "你已经领过了", activity if record:
if record.receive_count >= activity.user_limit:
return False, "你已经领过了", activity
return True, "可领取", activity return True, "可领取", activity

View File

@ -40,10 +40,10 @@ async def get_dashboard_info(
# 查询已下单用户数 # 查询已下单用户数
all_orders = db.query(ShippingOrderDB).all() all_orders = db.query(ShippingOrderDB).all()
completed_orders = [order for order in all_orders if order.status == OrderStatus.COMPLETED or order.status == OrderStatus.UNPAID] completed_orders = [order for order in all_orders if order.status == OrderStatus.COMPLETED]
has_order_user_count = len(set([order.userid for order in all_orders if order.status != OrderStatus.CANCELLED])) has_order_user_count = len(set([order.userid for order in all_orders if order.status != OrderStatus.CANCELLED]))
has_order_completed_user_count = len(set([order.userid for order in completed_orders if order.status == OrderStatus.COMPLETED or order.status == OrderStatus.UNPAID])) has_order_completed_user_count = len(set([order.userid for order in completed_orders if order.status == OrderStatus.COMPLETED]))
has_paid_user_count = len(set([order.userid for order in completed_orders if order.status == OrderStatus.COMPLETED and order.final_amount > 0])) has_paid_user_count = len(set([order.userid for order in completed_orders if order.status == OrderStatus.COMPLETED and order.final_amount > 0]))
order_count = len(completed_orders) order_count = len(completed_orders)
@ -169,8 +169,8 @@ async def get_deliveryman_dashboard_info(
result = [] result = []
for deliveryman in deliverymans: for deliveryman in deliverymans:
orders = db.query(ShippingOrderDB).filter(ShippingOrderDB.deliveryman_user_id == deliveryman.UserDB.userid, ShippingOrderDB.status.in_([OrderStatus.COMPLETED, OrderStatus.UNPAID])).all() orders = db.query(ShippingOrderDB).filter(ShippingOrderDB.deliveryman_user_id == deliveryman.UserDB.userid, ShippingOrderDB.status==OrderStatus.COMPLETED).all()
today_orders = db.query(ShippingOrderDB).filter(ShippingOrderDB.deliveryman_user_id == deliveryman.UserDB.userid, ShippingOrderDB.status.in_([OrderStatus.COMPLETED, OrderStatus.UNPAID]), ShippingOrderDB.completed_time >= datetime.now().date()).all() today_orders = [order for order in orders if order.completed_time.date() == datetime.now().date()]
result.append({ result.append({
"deliveryman_id": deliveryman.UserDB.userid, "deliveryman_id": deliveryman.UserDB.userid,
"deliveryman_name": deliveryman.UserDB.nickname, "deliveryman_name": deliveryman.UserDB.nickname,

View File

@ -228,18 +228,6 @@ async def pre_order(
message += f"{day}, " message += f"{day}, "
message = message[:-2] message = message[:-2]
return error_response(code=400, message=message) return error_response(code=400, message=message)
# 检查是否有配送员在线
# deliveryman_online = db.query(UserDB).filter(
# UserDB.roles.contains(UserRole.DELIVERYMAN),
# UserDB.community_id == request.community_id,
# UserDB.is_delivering == True
# ).first()
# if deliveryman_online is None:
# print(f"没有配送员在线, 无法下单")
# return error_response(code=400, message="没有配送员在线, 无法下单")
# 检查是否有未支付的订单 # 检查是否有未支付的订单
unpay_order = db.query(ShippingOrderDB).filter( unpay_order = db.query(ShippingOrderDB).filter(
@ -326,7 +314,7 @@ async def create_order(
more_station_price=price_info.more_station_price, more_station_price=price_info.more_station_price,
coupon_id=coupon_id, coupon_id=coupon_id,
final_amount=price_info.final_amount, final_amount=price_info.final_amount,
status=OrderStatus.CREATED, status=OrderStatus.UNPAID if price_info.final_amount > 0 else OrderStatus.CREATED,
delivery_method=order.delivery_method, delivery_method=order.delivery_method,
delivery_date=order.delivery_date, delivery_date=order.delivery_date,
is_first_order=is_first_order is_first_order=is_first_order
@ -634,7 +622,7 @@ async def deliveryman_get_order_status_count(
): ):
"""获取社区订单状态数量""" """获取社区订单状态数量"""
status_list = [OrderStatus.CREATED, OrderStatus.RECEIVED, OrderStatus.DELIVERING, OrderStatus.UNPAID, OrderStatus.COMPLETED] status_list = [OrderStatus.CREATED, OrderStatus.RECEIVED, OrderStatus.DELIVERING, OrderStatus.COMPLETED]
result = [] result = []
for status in status_list: for status in status_list:
@ -1236,11 +1224,8 @@ async def deliveryman_complete_order(
return error_response(code=400, message="只有配送中的订单才能标记为完成") return error_response(code=400, message="只有配送中的订单才能标记为完成")
try: try:
# 根据订单金额决定状态
if order.final_amount > 0: order.status = OrderStatus.COMPLETED # 无需支付,直接完成
order.status = OrderStatus.UNPAID # 需要支付
else:
order.status = OrderStatus.COMPLETED # 无需支付,直接完成
# 保存完成图片 # 保存完成图片
if complete_data.images: if complete_data.images:

View File

@ -20,6 +20,7 @@ from app.core.qcloud import qcloud_manager
from fastapi import BackgroundTasks from fastapi import BackgroundTasks
from app.core.mpmessage import sent_order_status_change_message from app.core.mpmessage import sent_order_status_change_message
from app.api.endpoints.order import calculate_delivery_share from app.api.endpoints.order import calculate_delivery_share
from app.core.utils import CommonUtils
router = APIRouter() router = APIRouter()
@ -60,7 +61,8 @@ async def create_additional_fee_request(
reason=fee_request.reason, reason=fee_request.reason,
photo_urls=fee_request.photo_urls, photo_urls=fee_request.photo_urls,
additional_fee_amount=fee_request.additional_fee_amount, additional_fee_amount=fee_request.additional_fee_amount,
result=AdditionalFeeResult.PENDING result=AdditionalFeeResult.PENDING,
fee_order_id=CommonUtils.generate_order_id('AD')
) )
db.add(db_fee_request) db.add(db_fee_request)

View File

@ -24,9 +24,15 @@ from app.core.point_manager import PointRecordType
from app.core.account import AccountManager from app.core.account import AccountManager
import logging import logging
from app.core.security import get_password_hash 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
router = APIRouter() router = APIRouter()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class PhoneNumberRequest(BaseModel): class PhoneNumberRequest(BaseModel):
login_code: str # 登录凭证 login_code: str # 登录凭证
phone_code: str # 手机号验证码 phone_code: str # 手机号验证码
@ -136,7 +142,17 @@ async def create_payment(
return error_response(code=404, message="订单不存在") return error_response(code=404, message="订单不存在")
description = "蜂快到家-配送费用" description = "蜂快到家-配送费用"
amount = order.final_amount amount = order.final_amount
if order_prefix == "AD": # 加价订单
order = db.query(OrderAdditionalFeeDB).filter(
OrderAdditionalFeeDB.fee_order_id == request.order_id
).first()
if not order:
logger.error(f"加价订单不存在: {request.order_id}")
return error_response(code=404, message="订单不存在")
description = "蜂快到家-加价费用"
amount = order.additional_fee_amount
elif order_prefix == "M": # 商家商品订单 elif order_prefix == "M": # 商家商品订单
order = db.query(MerchantOrderDB).filter( order = db.query(MerchantOrderDB).filter(
MerchantOrderDB.order_id == request.order_id MerchantOrderDB.order_id == request.order_id
@ -192,20 +208,20 @@ async def payment_notify(
data = await wechat.verify_payment_notify(request) data = await wechat.verify_payment_notify(request)
if not data: if not data:
print(f"回调数据验证失败: {data}") logger.error(f"回调数据验证失败: {data}")
return error_response(code=400, message="回调数据验证失败") return error_response(code=400, message="回调数据验证失败")
print(f"回调数据验证成功: {data}") logger.info(f"回调数据验证成功: {data}")
# 获取订单信息 # 获取订单信息
out_trade_no = data.get("out_trade_no") out_trade_no = data.get("out_trade_no")
transaction_id = data.get("transaction_id") transaction_id = data.get("transaction_id")
trade_state_desc = data.get("trade_state_desc") trade_state_desc = data.get("trade_state_desc")
success_time = data.get("success_time") success_time = data.get("success_time")
print(f"out_trade_no: {out_trade_no}") logger.info(f"out_trade_no: {out_trade_no}")
print(f"transaction_id: {transaction_id}") logger.info(f"transaction_id: {transaction_id}")
print(f"trade_state_desc: {trade_state_desc}") logger.info(f"trade_state_desc: {trade_state_desc}")
print(f"success_time: {success_time}") logger.info(f"success_time: {success_time}")
if not all([out_trade_no, transaction_id, trade_state_desc]) or trade_state_desc != "支付成功": if not all([out_trade_no, transaction_id, trade_state_desc]) or trade_state_desc != "支付成功":
return error_response(code=400, message="缺少必要的订单信息或支付未成功") return error_response(code=400, message="缺少必要的订单信息或支付未成功")
@ -222,12 +238,42 @@ async def payment_notify(
if trade_state_desc == "支付成功": if trade_state_desc == "支付成功":
# 更新订单状态 # 更新订单状态
if order.deliveryman_user_id:
order.status = OrderStatus.COMPLETED # 支付成功后状态为已完成
else:
order.status = OrderStatus.CREATED # 支付成功后状态为已创建
order.pay_status = True order.pay_status = True
order.status = OrderStatus.COMPLETED # 支付成功后状态为已完成
order.completed_time = datetime.now() order.completed_time = datetime.now()
order.transaction_id = transaction_id order.transaction_id = transaction_id
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00')) order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
elif out_trade_no.startswith("AD"): # 加价订单
additon_fee_order = db.query(OrderAdditionalFeeDB).filter(
OrderAdditionalFeeDB.fee_order_id == out_trade_no
).first()
if not additon_fee_order:
return error_response(code=404, message="订单不存在")
if trade_state_desc == "支付成功":
# 更新订单状态
additon_fee_order.result = AdditionalFeeResult.ACCEPTED
additon_fee_order.transaction_id = transaction_id
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == additon_fee_order.orderid
).first()
if not order:
return error_response(code=404, message="订单不存在")
order.additional_fee_amount += float(additon_fee_order.additional_fee_amount)
order.final_amount += float(additon_fee_order.additional_fee_amount)
logger.info(f"加价订单支付成功: {additon_fee_order.orderid}")
# 重新计算配送员配送费用
order.delivery_share = calculate_delivery_share(order, db)
elif out_trade_no.startswith("M"): # 商家商品订单 elif out_trade_no.startswith("M"): # 商家商品订单
# 查询商户订单 # 查询商户订单
@ -299,13 +345,28 @@ async def payment_notify(
else: else:
return error_response(code=400, message="未知的订单类型") return error_response(code=400, message="未知的订单类型")
# 在支付回调处理中添加记录
payment_record = WechatPaymentRecordDB(
out_trade_no=out_trade_no,
transaction_id=transaction_id,
trade_state=data.get("trade_state"),
trade_state_desc=trade_state_desc,
success_time=datetime.fromisoformat(success_time) if success_time else None,
total_amount=float(data.get("amount", {}).get("total", 0)) / 100,
payer_total=float(data.get("amount", {}).get("payer_total", 0)) / 100,
payer_openid=data.get("payer", {}).get("openid"),
bank_type=data.get("bank_type"),
promotion_detail=data.get("promotion_detail"),
raw_data=data
)
db.add(payment_record)
db.commit() db.commit()
# 返回成功 # 返回成功
return success_response(message="支付成功") return success_response(message="支付成功")
except Exception as e: except Exception as e:
print(f"处理支付回调失败: {str(e)}") logger.error(f"处理支付回调失败: {str(e)}")
db.rollback() db.rollback()
return error_response(code=500, message=f"处理支付回调失败: {str(e)}") return error_response(code=500, message=f"处理支付回调失败: {str(e)}")
@ -321,10 +382,10 @@ async def refund_notify(
data = await wechat.verify_payment_notify(request) data = await wechat.verify_payment_notify(request)
if not data: if not data:
print(f"退款回调数据验证失败: {data}") logger.error(f"退款回调数据验证失败: {data}")
return error_response(code=400, message="回调数据验证失败") return error_response(code=400, message="回调数据验证失败")
print(f"退款回调数据验证成功: {data}") logger.info(f"退款回调数据验证成功: {data}")
# 获取退款信息 # 获取退款信息
out_trade_no = data.get("out_trade_no") # 订单号 out_trade_no = data.get("out_trade_no") # 订单号
@ -378,6 +439,6 @@ async def refund_notify(
return success_response(message="退款处理成功") return success_response(message="退款处理成功")
except Exception as e: except Exception as e:
print(f"处理退款回调失败: {str(e)}") logger.error(f"处理退款回调失败: {str(e)}")
db.rollback() db.rollback()
return error_response(code=500, message=f"处理退款回调失败: {str(e)}") return error_response(code=500, message=f"处理退款回调失败: {str(e)}")

View File

@ -16,6 +16,7 @@ class OrderAdditionalFeeDB(Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
orderid = Column(String(32), ForeignKey("shipping_orders.orderid"), nullable=False, index=True) orderid = Column(String(32), ForeignKey("shipping_orders.orderid"), nullable=False, index=True)
fee_order_id = Column(String(32), nullable=False, unique=True) # 子订单号,用于支付标识
order_user_id = Column(Integer, ForeignKey("users.userid"), nullable=False) order_user_id = Column(Integer, ForeignKey("users.userid"), nullable=False)
deliveryman_id = Column(Integer, ForeignKey("users.userid"), nullable=False) deliveryman_id = Column(Integer, ForeignKey("users.userid"), nullable=False)
reason = Column(String(200), nullable=False) reason = Column(String(200), nullable=False)
@ -24,6 +25,7 @@ class OrderAdditionalFeeDB(Base):
result = Column(Enum(AdditionalFeeResult), nullable=False, default=AdditionalFeeResult.PENDING) result = Column(Enum(AdditionalFeeResult), nullable=False, default=AdditionalFeeResult.PENDING)
create_time = Column(DateTime(timezone=True), server_default=func.now()) create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now())
transaction_id = Column(String(64), nullable=True) # 微信支付交易号
# Pydantic 模型 # Pydantic 模型
class OrderAdditionalFeeCreate(BaseModel): class OrderAdditionalFeeCreate(BaseModel):

View File

@ -0,0 +1,50 @@
# app/models/wechat_payment.py
from sqlalchemy import Column, Integer, String, DateTime, DECIMAL, JSON
from sqlalchemy.sql import func
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any, List
from datetime import datetime
from .database import Base
class WechatPaymentRecordDB(Base):
"""微信支付记录表"""
__tablename__ = "wechat_payment_records"
id = Column(Integer, primary_key=True, autoincrement=True)
out_trade_no = Column(String(32), nullable=False, index=True, comment='商户订单号')
transaction_id = Column(String(64), index=True, comment='微信支付交易号')
trade_state = Column(String(32), comment='交易状态')
trade_state_desc = Column(String(256), comment='交易状态描述')
success_time = Column(DateTime(timezone=True), comment='支付成功时间')
total_amount = Column(DECIMAL(10, 2), comment='订单总金额')
payer_total = Column(DECIMAL(10, 2), comment='用户实际支付金额')
currency = Column(String(16), default='CNY', comment='货币类型')
payer_openid = Column(String(128), comment='支付者openid')
attach = Column(String(128), comment='附加数据')
bank_type = Column(String(32), comment='付款银行类型')
promotion_detail = Column(JSON, 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 WechatPaymentRecordInfo(BaseModel):
id: int
out_trade_no: str
transaction_id: Optional[str] = None
trade_state: Optional[str] = None
trade_state_desc: Optional[str] = None
success_time: Optional[datetime] = None
total_amount: Optional[float] = None
payer_total: Optional[float] = None
currency: str = 'CNY'
payer_openid: Optional[str] = None
attach: Optional[str] = None
bank_type: Optional[str] = None
promotion_detail: Optional[List[Dict[str, Any]]] = None
raw_data: Optional[Dict[str, Any]] = None
create_time: datetime
update_time: Optional[datetime] = None
class Config:
from_attributes = True

View File

@ -162,4 +162,18 @@ ADD CONSTRAINT fk_merchant_community
FOREIGN KEY (community_id) REFERENCES communities(id) FOREIGN KEY (community_id) REFERENCES communities(id)
--====FINISH 3.24==== --====FINISH 3.24====
-- 为 order_additional_fees 表添加 fee_order_id 字段
ALTER TABLE order_additional_fees
ADD COLUMN fee_order_id VARCHAR(32) NOT NULL COMMENT '子订单号,用于支付标识';
-- 创建唯一索引
ALTER TABLE order_additional_fees
ADD UNIQUE INDEX uix_fee_order_id (fee_order_id);
-- 为 order_additional_fees 表添加 transaction_id 字段
ALTER TABLE order_additional_fees
ADD COLUMN transaction_id VARCHAR(64) NULL COMMENT '微信支付交易号';

View File

@ -54,7 +54,7 @@ async def daily_community_order_statistics():
communities c ON o.address_community_id = c.id communities c ON o.address_community_id = c.id
WHERE WHERE
o.completed_time BETWEEN :start_time AND :end_time o.completed_time BETWEEN :start_time AND :end_time
AND o.status in ('COMPLETED', 'UNPAID') AND o.status = 'COMPLETED'
GROUP BY GROUP BY
c.id, c.name c.id, c.name
ORDER BY ORDER BY

Binary file not shown.