feat(points): 新增积分赠送
This commit is contained in:
39
core/routers/card/actions.py
Normal file
39
core/routers/card/actions.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Project : X25020501_card_book
|
||||
# @File : actions.py.py
|
||||
# @Date : 2025/5/7 20:38
|
||||
# @Software : PyCharm
|
||||
# @Author : xingc
|
||||
# @Desc :
|
||||
import logging
|
||||
|
||||
from core.base.schema import ProductCategory
|
||||
from core.db.crud import CRUD
|
||||
from core.db.models import User, Product
|
||||
from core.routers.auth.schema import LoginUser
|
||||
from core.routers.pay.actions import actions_handler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def reward_points_after_uploading_pictures(
|
||||
db_crud: CRUD,
|
||||
gift_product_id: int,
|
||||
login_user: LoginUser
|
||||
):
|
||||
product: Product = await db_crud.get(
|
||||
model=Product, filters={
|
||||
'id': gift_product_id,
|
||||
'category': ProductCategory.GIFT
|
||||
}
|
||||
)
|
||||
if not product:
|
||||
logger.warning(f'Product not found -> {gift_product_id}')
|
||||
return
|
||||
|
||||
user: User = await db_crud.get(model=User, filters={'user_id': login_user.user_id})
|
||||
|
||||
try:
|
||||
await actions_handler(db_crud, product, user)
|
||||
except Exception as e:
|
||||
logger.error(f'Reward Points After Uploading Pictures -> {e}')
|
||||
@@ -23,6 +23,7 @@ from core.routers.auth.services import get_current_user_form_http
|
||||
from core.utils.helper import generate_keyname, check_picture_for_empty
|
||||
|
||||
from . import schema
|
||||
from .actions import reward_points_after_uploading_pictures
|
||||
from .scraper import card_scraper
|
||||
from .services import check_user_card_created_permission
|
||||
|
||||
@@ -190,17 +191,18 @@ async def created_card(
|
||||
login_user: LoginUser = Depends(get_current_user_form_http),
|
||||
db_session: AsyncSession = Depends(get_async_session)
|
||||
):
|
||||
card_crud = CRUD(db_session, Card)
|
||||
db_crud = CRUD(db_session, Card)
|
||||
# 确认用户存卡权限
|
||||
if await check_user_card_created_permission(
|
||||
db_session, login_user=login_user
|
||||
) is False:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail=f'非会员仅支持存入{settings.USER_MAX_CREATED_CARD_NUM}张卡片'
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'非会员仅支持存入{settings.USER_MAX_CREATED_CARD_NUM}张卡片'
|
||||
)
|
||||
|
||||
# 卡片库查询
|
||||
card: Card = await card_crud.get(filters={'cert_number': payload.cert_number})
|
||||
card: Card = await db_crud.get(filters={'cert_number': payload.cert_number})
|
||||
if payload.source.value != 'other':
|
||||
if card is None:
|
||||
# 卡片缓存库转正至卡片库, 重新查询保障数据准确性
|
||||
@@ -208,7 +210,7 @@ async def created_card(
|
||||
cache_card = await cache_card_crud.get(
|
||||
filters={'cert_number': payload.cert_number, 'source': payload.source.value}
|
||||
)
|
||||
card = await card_crud.create(
|
||||
card = await db_crud.create(
|
||||
data={
|
||||
**cache_card.data,
|
||||
'category': payload.category,
|
||||
@@ -232,17 +234,23 @@ async def created_card(
|
||||
if card_picture.get(key) is None:
|
||||
card_picture[key] = value
|
||||
|
||||
await card_crud.update(
|
||||
await db_crud.update(
|
||||
data={
|
||||
'card_picture': card_picture,
|
||||
'perfect_user_id': login_user.user_id,
|
||||
},
|
||||
filters={'id': card.id}
|
||||
)
|
||||
# 上传图片奖励
|
||||
if payload.reward and settings.UPLOAD_REWARD_POINTS_GIFT_ID > 0:
|
||||
await reward_points_after_uploading_pictures(
|
||||
db_crud, gift_product_id=settings.UPLOAD_REWARD_POINTS_GIFT_ID, login_user=login_user
|
||||
)
|
||||
|
||||
|
||||
else:
|
||||
if card is None:
|
||||
card: Card = await card_crud.create(
|
||||
card: Card = await db_crud.create(
|
||||
data={
|
||||
**payload.dict(exclude_none=True, exclude={'reward'}),
|
||||
'create_user_id': login_user.user_id,
|
||||
@@ -251,12 +259,12 @@ async def created_card(
|
||||
filters={'cert_number': payload.cert_number, 'source': payload.source.value}
|
||||
)
|
||||
|
||||
collection_crud = CRUD(db_session, UserCollection)
|
||||
record = {
|
||||
'user_id': login_user.user_id,
|
||||
'card_id': card.id
|
||||
}
|
||||
result = await collection_crud.create(
|
||||
await db_crud.create(
|
||||
model=UserCollection,
|
||||
data=record,
|
||||
filters=record
|
||||
)
|
||||
@@ -299,7 +307,8 @@ async def display_card_status(
|
||||
db_session, login_user=login_user, other_conditions={'displayed': True}
|
||||
) is False and action == 'displayed':
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST, detail=f'非会员仅支持展示{settings.USER_MAX_CREATED_CARD_NUM}张卡片'
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f'非会员仅支持展示{settings.USER_MAX_CREATED_CARD_NUM}张卡片'
|
||||
)
|
||||
|
||||
db_crud = CRUD(db_session, UserCollection)
|
||||
|
||||
@@ -13,7 +13,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from core.base.schema import ProductCategory
|
||||
from core.db.crud import CRUD
|
||||
from core.db.engine import get_async_session
|
||||
from core.db.models import User, Order, Product
|
||||
from core.db.models import User, Order, Product, PointsTransaction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,7 +30,7 @@ async def actions_after_payment(
|
||||
logger.error(f'Order not found -> {order_id}')
|
||||
return
|
||||
|
||||
product: Product = await db_crud.get(model=Product, filters={'product_id': order.product_id})
|
||||
product: Product = await db_crud.get(model=Product, filters={'id': order.product_id})
|
||||
if not product:
|
||||
logger.warning(f'Product not found -> {order.product_id}')
|
||||
return
|
||||
@@ -40,30 +40,62 @@ async def actions_after_payment(
|
||||
logger.warning(f'User not found -> {order.order_id}')
|
||||
return
|
||||
|
||||
if product.action == ProductCategory.VIP:
|
||||
vip_expire_date = (
|
||||
user.vip_expire_date or datetime.now()
|
||||
) + timedelta(days=product.number)
|
||||
await db_crud.update(
|
||||
model=User,
|
||||
data={
|
||||
'vip_expire_date': vip_expire_date.date()
|
||||
},
|
||||
filters={'user_id': order.user_id}
|
||||
await actions_handler(db_crud, product, user)
|
||||
if product.gift_id:
|
||||
gift_product = await db_crud.get(
|
||||
model=Product, filters={
|
||||
'id': product.gift_id,
|
||||
'category': ProductCategory.GIFT
|
||||
}
|
||||
)
|
||||
elif product.action == ProductCategory.POINTS:
|
||||
points = (
|
||||
user.points or 0
|
||||
) + product.number
|
||||
await db_crud.update(
|
||||
model=User,
|
||||
data={
|
||||
'points': points
|
||||
},
|
||||
filters={'user_id': order.user_id}
|
||||
)
|
||||
else:
|
||||
logger.error(f'Unknown action -> {product.action}')
|
||||
await actions_handler(db_crud, gift_product, user)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Payment Actions Exception occurred -> {e}')
|
||||
logger.exception(e)
|
||||
logger.exception(e)
|
||||
|
||||
|
||||
async def actions_handler(db_crud: CRUD, product: Product, user: User):
|
||||
if product.action == ProductCategory.VIP:
|
||||
vip_expire_date = (
|
||||
user.vip_expire_date or datetime.now()
|
||||
) + timedelta(days=product.number)
|
||||
await db_crud.update(
|
||||
model=User,
|
||||
data={
|
||||
'vip_expire_date': vip_expire_date.date()
|
||||
},
|
||||
filters={'user_id': user.user_id}
|
||||
)
|
||||
elif product.action == ProductCategory.POINTS:
|
||||
points = (
|
||||
user.points or 0
|
||||
) + product.number
|
||||
await db_crud.update(
|
||||
model=User,
|
||||
data={
|
||||
'points': points
|
||||
},
|
||||
filters={'user_id': user.user_id}
|
||||
)
|
||||
|
||||
if product.category.value == 'gift':
|
||||
transaction_type = 3
|
||||
else:
|
||||
transaction_type = 1
|
||||
|
||||
await db_crud.update(
|
||||
model=PointsTransaction,
|
||||
data={
|
||||
'user_id': user.user_id,
|
||||
'transaction_type': transaction_type,
|
||||
'points': product.number,
|
||||
'product_id': product.id,
|
||||
'balance': points,
|
||||
'description': f'{product.name} - {product.number}'
|
||||
},
|
||||
filters={'id': -1}
|
||||
)
|
||||
|
||||
else:
|
||||
logger.error(f'Unknown action -> {product.action}')
|
||||
|
||||
@@ -14,7 +14,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from core.base import schema as base_schema
|
||||
from core.db.crud import CRUD
|
||||
from core.db.engine import get_async_session
|
||||
from core.db.models import Order
|
||||
from core.db.models import Order, Product
|
||||
from core.routers.auth.schema import LoginUser
|
||||
from core.routers.auth.services import get_current_user_form_http
|
||||
from core.utils.helper import generate_keyname, generate_order_number
|
||||
@@ -55,6 +55,14 @@ async def create_order(
|
||||
login_user: LoginUser = Depends(get_current_user_form_http),
|
||||
db_session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
db_crud = CRUD(db_session, Order)
|
||||
product = await db_crud.get(model=Product, filters={'id': payload.product_id})
|
||||
if product is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, detail='产品不存在')
|
||||
|
||||
if product.number != payload.total_fee:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail='产品费用不合法')
|
||||
|
||||
client_ip = (
|
||||
request.headers.get('X-Real-IP') or
|
||||
request.headers.get('x-real-ip') or
|
||||
@@ -67,7 +75,7 @@ async def create_order(
|
||||
create_ip=client_ip
|
||||
)
|
||||
payment_params = wechat_pay_api.generate_payment_params(prepay_id)
|
||||
db_crud = CRUD(db_session, Order)
|
||||
|
||||
order: Order = await db_crud.create(
|
||||
data={
|
||||
'order_id': out_trade_no,
|
||||
@@ -112,7 +120,7 @@ async def wechat_notify(
|
||||
# 处理支付结果
|
||||
db_crud = CRUD(db_session, Order)
|
||||
record = {
|
||||
'out_trade_no': params['out_trade_no'],
|
||||
'order_id': params['out_trade_no'],
|
||||
'transaction_id': params['transaction_id']
|
||||
}
|
||||
if params['return_code'] == 'SUCCESS' and params['result_code'] == 'SUCCESS':
|
||||
|
||||
@@ -21,7 +21,7 @@ class PaymentParamsOut(BaseModel):
|
||||
timeStamp: str
|
||||
nonceStr: str
|
||||
package: str
|
||||
package: str
|
||||
paySign: str
|
||||
signType: str
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.base import schema as base_schema
|
||||
@@ -38,6 +39,24 @@ async def get_products(
|
||||
):
|
||||
db_crud = CRUD(db_session, Product)
|
||||
products = await db_crud.get_all(filters={'category': category})
|
||||
gift_product_ids = set()
|
||||
for product in products:
|
||||
if product.gift_id:
|
||||
gift_product_ids.add(product.gift_id)
|
||||
|
||||
gift_products = {
|
||||
p.id: p
|
||||
for p in
|
||||
await db_crud.get_all(
|
||||
filters={
|
||||
'category': base_schema.ProductCategory.GIFT,
|
||||
'id__in': gift_product_ids
|
||||
}
|
||||
)
|
||||
}
|
||||
for product in products:
|
||||
product.gift_product = gift_products.get(product.gift_id)
|
||||
|
||||
return {
|
||||
'data': products
|
||||
}
|
||||
|
||||
@@ -10,10 +10,14 @@ from pydantic import BaseModel
|
||||
from core.base.schema import ProductCategory
|
||||
|
||||
|
||||
class ProductOut(BaseModel):
|
||||
class Product(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
category: ProductCategory
|
||||
price: int
|
||||
number: int
|
||||
description: str | None
|
||||
|
||||
|
||||
class ProductOut(Product):
|
||||
gift_product: Product | None
|
||||
|
||||
Reference in New Issue
Block a user