diff --git a/app/api/endpoints/merchant_order.py b/app/api/endpoints/merchant_order.py index a8137fc..1879921 100644 --- a/app/api/endpoints/merchant_order.py +++ b/app/api/endpoints/merchant_order.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from sqlalchemy import func -from typing import List +from typing import List, Optional from app.models.merchant_order import ( MerchantOrderDB, MerchantOrderCreate, @@ -21,6 +21,13 @@ from app.core.wechat import WeChatClient from pydantic import BaseModel from app.core.config import settings from app.core.utils import CommonUtils +from sqlalchemy.sql import text +import qrcode +import io +from fastapi import UploadFile +from app.core.qcloud import qcloud_manager +from app.core.imageprocessor import process_image, ImageFormat +from starlette.datastructures import Headers router = APIRouter() @@ -268,6 +275,8 @@ async def confirm_refund( @router.get("/{order_id}", response_model=ResponseModel) async def get_order_detail( order_id: str, + longitude: Optional[float] = None, + latitude: Optional[float] = None, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): @@ -279,7 +288,13 @@ async def get_order_detail( MerchantDB.name.label('merchant_name'), MerchantDB.latitude.label('merchant_latitude'), MerchantDB.longitude.label('merchant_longitude'), - MerchantDB.phone.label('merchant_phone') + MerchantDB.phone.label('merchant_phone'), + text("CASE WHEN :lat IS NOT NULL AND :lon IS NOT NULL THEN " + "ST_Distance_Sphere(point(merchants.longitude, merchants.latitude), point(:lon, :lat)) " + "ELSE NULL END as distance").params( + lat=latitude, + lon=longitude + ) if longitude and latitude else text("NULL as distance") ).join( MerchantProductDB, MerchantOrderDB.merchant_product_id == MerchantProductDB.id @@ -317,7 +332,9 @@ async def get_order_detail( "merchant_name": order.merchant_name, "merchant_latitude": order.merchant_latitude, "merchant_longitude": order.merchant_longitude, - "merchant_phone": order.merchant_phone + "merchant_phone": order.merchant_phone, + # 距离信息 + "distance": round(order.distance) if order.distance else None } return success_response(data=order_data) @@ -391,4 +408,63 @@ async def refund_merchant_order( except Exception as e: db.rollback() - return error_response(code=500, message=f"处理退款失败: {str(e)}") \ No newline at end of file + return error_response(code=500, message=f"处理退款失败: {str(e)}") + +@router.get("/{order_id}/verify-qrcode", response_model=ResponseModel) +async def get_order_qrcode( + order_id: str, + db: Session = Depends(get_db), + current_user: UserDB = Depends(get_current_user) +): + """获取订单核销二维码""" + # 查询订单 + order = db.query(MerchantOrderDB).filter( + MerchantOrderDB.order_id == order_id + ).first() + + if not order: + return error_response(code=404, message="订单不存在") + + # 如果已经有二维码,直接返回 + if order.qrcode_url: + url = process_image(order.qrcode_url).thumbnail(800, 800).format(ImageFormat.WEBP).quality(90).build() + return success_response(data={"qrcode_url":url}) + + try: + # 生成二维码 + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=1, + ) + qr.add_data(order.order_verify_code) + qr.make(fit=True) + + # 创建图片 + img = qr.make_image(fill_color="black", back_color="white") + + # 将图片转换为字节流 + img_byte_arr = io.BytesIO() + img.save(img_byte_arr, format='PNG') + img_byte_arr.seek(0) + + # 创建 UploadFile 对象 + file = UploadFile( + file=img_byte_arr, + filename=f"qrcode_{order_id}.png", + headers=Headers({"content-type": "image/png"}) + ) + + # 上传到腾讯云 + url = await qcloud_manager.upload_file(file) + + # 更新订单的二维码URL + order.qrcode_url = url + db.commit() + + process_url = process_image(url).thumbnail(800, 800).format(ImageFormat.WEBP).quality(90).build() + return success_response(data={"qrcode_url": process_url}) + except Exception as e: + db.rollback() + return error_response(code=500, message=f"生成二维码失败: {str(e)}") \ No newline at end of file diff --git a/app/models/merchant_order.py b/app/models/merchant_order.py index 0ba04ed..c155ecd 100644 --- a/app/models/merchant_order.py +++ b/app/models/merchant_order.py @@ -21,6 +21,7 @@ class MerchantOrderDB(Base): id = Column(Integer, primary_key=True, autoincrement=True) order_id = Column(String(15), unique=True, nullable=False) + qrcode_url = Column(String(200)) # 核销码二维码图片地址 user_id = Column(Integer, ForeignKey("users.userid"), nullable=False) merchant_product_id = Column(Integer, ForeignKey("merchant_products.id"), nullable=False) order_amount = Column(DECIMAL(10,2), nullable=False) diff --git a/requirements.txt b/requirements.txt index 4403c45..7ca76cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,6 @@ tencentcloud-sdk-python==3.0.1035 cos-python-sdk-v5 bcrypt aiohttp==3.9.1 -cryptography==42.0.2 \ No newline at end of file +cryptography==42.0.2 +qrcode>=7.3.1 +pillow>=9.0.0 \ No newline at end of file