添加素材列表
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional, List
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
from fastapi import APIRouter, Query, Depends, Body
|
from fastapi import APIRouter, Query, Depends, Body
|
||||||
@@ -6,11 +6,13 @@ from sqlalchemy import select, func
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.models.user import User
|
from app.models.user import User
|
||||||
|
from app.models.resources_material import ResourcesMaterial
|
||||||
from app.models.material_cost import MaterialCost
|
from app.models.material_cost import MaterialCost
|
||||||
from app.models.user_oauth import UserOAuth
|
from app.models.user_oauth import UserOAuth
|
||||||
from app.models.user_oauth_account import UserOAuthAccount
|
from app.models.user_oauth_account import UserOAuthAccount
|
||||||
from app.dependencies import get_current_user, get_db
|
from app.dependencies import get_current_user, get_db, get_admin_user
|
||||||
from app.services.material_consumption_queue import sync_all_advertisers_consumption, _fetch_and_save_consumption
|
from app.services.material_consumption_queue import sync_all_advertisers_consumption, _fetch_and_save_consumption
|
||||||
|
from app.services.material_consumption_service import get_consumption_list, format_consumption_response
|
||||||
|
|
||||||
router = APIRouter(prefix="/material-consumption", tags=["material-consumption"])
|
router = APIRouter(prefix="/material-consumption", tags=["material-consumption"])
|
||||||
|
|
||||||
@@ -20,146 +22,26 @@ router = APIRouter(prefix="/material-consumption", tags=["material-consumption"]
|
|||||||
summary="查询素材消耗列表",
|
summary="查询素材消耗列表",
|
||||||
description="查询当前用户的素材消耗列表",
|
description="查询当前用户的素材消耗列表",
|
||||||
)
|
)
|
||||||
async def get_consumption_list(
|
async def user_consumption_list(
|
||||||
page: int = Query(1, ge=1, description="页码"),
|
page: int = Query(1, ge=1, description="页码"),
|
||||||
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
||||||
advertiser_id: Optional[str] = Query(None, description="广告主ID筛选"),
|
advertiser_id: Optional[str] = Query(None, description="广告主ID筛选"),
|
||||||
start_date: Optional[str] = Query(None, description="开始日期"),
|
consume_date: Optional[List[str]] = Query(None, description="消耗日期范围,格式: ['开始日期','结束日期']"),
|
||||||
end_date: Optional[str] = Query(None, description="结束日期"),
|
|
||||||
current_user: User = Depends(get_current_user),
|
current_user: User = Depends(get_current_user),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
) -> Any | dict:
|
) -> Any | dict:
|
||||||
offset = (page - 1) * page_size
|
consumptions, total = await get_consumption_list(
|
||||||
|
db=db,
|
||||||
query = (
|
page=page,
|
||||||
select(MaterialCost)
|
page_size=page_size,
|
||||||
.join(
|
advertiser_id=advertiser_id,
|
||||||
UserOAuth,
|
consume_date=consume_date,
|
||||||
MaterialCost.oauth_id == UserOAuth.id,
|
current_user=current_user,
|
||||||
)
|
|
||||||
.where(
|
|
||||||
UserOAuth.user_id == current_user.id,
|
|
||||||
MaterialCost.deleted_at.is_(None),
|
|
||||||
UserOAuth.deleted_at.is_(None),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if advertiser_id:
|
|
||||||
query = query.where(MaterialCost.advertiser_id == advertiser_id)
|
|
||||||
|
|
||||||
if start_date:
|
|
||||||
start_date_obj = datetime.strptime(start_date, "%Y-%m-%d").date()
|
|
||||||
query = query.where(MaterialCost.consume_date >= start_date_obj)
|
|
||||||
|
|
||||||
if end_date:
|
|
||||||
end_date_obj = datetime.strptime(end_date, "%Y-%m-%d").date()
|
|
||||||
query = query.where(MaterialCost.consume_date <= end_date_obj)
|
|
||||||
|
|
||||||
result = await db.execute(
|
|
||||||
query.order_by(MaterialCost.consume_date.desc())
|
|
||||||
.offset(offset)
|
|
||||||
.limit(page_size)
|
|
||||||
)
|
|
||||||
consumptions = result.scalars().all()
|
|
||||||
|
|
||||||
count_query = (
|
|
||||||
select(func.count(MaterialCost.id))
|
|
||||||
.join(
|
|
||||||
UserOAuth,
|
|
||||||
MaterialCost.oauth_id == UserOAuth.id,
|
|
||||||
)
|
|
||||||
.where(
|
|
||||||
UserOAuth.user_id == current_user.id,
|
|
||||||
MaterialCost.deleted_at.is_(None),
|
|
||||||
UserOAuth.deleted_at.is_(None),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if advertiser_id:
|
|
||||||
count_query = count_query.where(MaterialCost.advertiser_id == advertiser_id)
|
|
||||||
|
|
||||||
if start_date:
|
|
||||||
start_date_obj = datetime.strptime(start_date, "%Y-%m-%d").date()
|
|
||||||
count_query = count_query.where(MaterialCost.consume_date >= start_date_obj)
|
|
||||||
|
|
||||||
if end_date:
|
|
||||||
end_date_obj = datetime.strptime(end_date, "%Y-%m-%d").date()
|
|
||||||
count_query = count_query.where(MaterialCost.consume_date <= end_date_obj)
|
|
||||||
|
|
||||||
total_result = await db.execute(count_query)
|
|
||||||
total = total_result.scalar_one()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"code": 0,
|
"code": 0,
|
||||||
"data": [
|
"data": format_consumption_response(consumptions),
|
||||||
{
|
|
||||||
"id": consumption.id,
|
|
||||||
"advertiser_id": consumption.advertiser_id,
|
|
||||||
"material_id": consumption.material_id,
|
|
||||||
"consume_date": consumption.consume_date.isoformat() if consumption.consume_date else None,
|
|
||||||
"stat_cost": consumption.stat_cost,
|
|
||||||
"show_cnt": consumption.show_cnt,
|
|
||||||
"cpm_platform": consumption.cpm_platform,
|
|
||||||
"click_cnt": consumption.click_cnt,
|
|
||||||
"ctr": consumption.ctr,
|
|
||||||
"cpc_platform": consumption.cpc_platform,
|
|
||||||
"convert_cnt": consumption.convert_cnt,
|
|
||||||
"conversion_cost": consumption.conversion_cost,
|
|
||||||
"conversion_rate": consumption.conversion_rate,
|
|
||||||
"deep_convert_cnt": consumption.deep_convert_cnt,
|
|
||||||
"deep_convert_cost": consumption.deep_convert_cost,
|
|
||||||
"deep_convert_rate": consumption.deep_convert_rate,
|
|
||||||
"active": consumption.active,
|
|
||||||
"active_cost": consumption.active_cost,
|
|
||||||
"active_rate": consumption.active_rate,
|
|
||||||
"active_register": consumption.active_register,
|
|
||||||
"active_register_cost": consumption.active_register_cost,
|
|
||||||
"active_register_rate": consumption.active_register_rate,
|
|
||||||
"attribution_next_day_open_cnt": consumption.attribution_next_day_open_cnt,
|
|
||||||
"attribution_next_day_open_cost": consumption.attribution_next_day_open_cost,
|
|
||||||
"attribution_next_day_open_rate": consumption.attribution_next_day_open_rate,
|
|
||||||
"active_pay": consumption.active_pay,
|
|
||||||
"active_pay_cost": consumption.active_pay_cost,
|
|
||||||
"active_pay_rate": consumption.active_pay_rate,
|
|
||||||
"phone": consumption.phone,
|
|
||||||
"form": consumption.form,
|
|
||||||
"download_start": consumption.download_start,
|
|
||||||
"form_submit": consumption.form_submit,
|
|
||||||
"button": consumption.button,
|
|
||||||
"view": consumption.view,
|
|
||||||
"message": consumption.message,
|
|
||||||
"consult": consumption.consult,
|
|
||||||
"consult_effective": consumption.consult_effective,
|
|
||||||
"shopping": consumption.shopping,
|
|
||||||
"customer_effective": consumption.customer_effective,
|
|
||||||
"attribution_game_in_app_ltv_1day": consumption.attribution_game_in_app_ltv_1day,
|
|
||||||
"attribution_game_in_app_roi_1day": consumption.attribution_game_in_app_roi_1day,
|
|
||||||
"loan_completion": consumption.loan_completion,
|
|
||||||
"loan_completion_cost": consumption.loan_completion_cost,
|
|
||||||
"loan_completion_rate": consumption.loan_completion_rate,
|
|
||||||
"loan_credit": consumption.loan_credit,
|
|
||||||
"loan_credit_cost": consumption.loan_credit_cost,
|
|
||||||
"loan_credit_rate": consumption.loan_credit_rate,
|
|
||||||
"in_app_order_gmv": consumption.in_app_order_gmv,
|
|
||||||
"in_app_order_roi": consumption.in_app_order_roi,
|
|
||||||
"in_app_pay_gmv": consumption.in_app_pay_gmv,
|
|
||||||
"in_app_pay_roi": consumption.in_app_pay_roi,
|
|
||||||
"total_play": consumption.total_play,
|
|
||||||
"valid_play": consumption.valid_play,
|
|
||||||
"valid_play_cost": consumption.valid_play_cost,
|
|
||||||
"valid_play_rate": consumption.valid_play_rate,
|
|
||||||
"valid_play_of_mille": consumption.valid_play_of_mille,
|
|
||||||
"valid_play_cost_of_mille": consumption.valid_play_cost_of_mille,
|
|
||||||
"average_play_time_per_play": consumption.average_play_time_per_play,
|
|
||||||
"play_over_rate": consumption.play_over_rate,
|
|
||||||
"dy_like": consumption.dy_like,
|
|
||||||
"dy_comment": consumption.dy_comment,
|
|
||||||
"dy_share": consumption.dy_share,
|
|
||||||
"report_cnt": consumption.report_cnt,
|
|
||||||
"created_at": consumption.created_at,
|
|
||||||
}
|
|
||||||
for consumption in consumptions
|
|
||||||
],
|
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"page": page,
|
"page": page,
|
||||||
"page_size": page_size,
|
"page_size": page_size,
|
||||||
@@ -171,27 +53,55 @@ async def get_consumption_list(
|
|||||||
@router.get(
|
@router.get(
|
||||||
"/sync",
|
"/sync",
|
||||||
summary="手动同步素材消耗",
|
summary="手动同步素材消耗",
|
||||||
description="手动触发素材消耗同步任务,加入队列顺序执行",
|
description="手动触发当前用户授权的广告主的素材消耗同步任务,加入队列顺序执行",
|
||||||
)
|
)
|
||||||
async def sync_consumption(
|
async def sync_consumption(
|
||||||
date: str = Query(None, description="同步日期,默认为昨天"),
|
date: str = Query(None, description="同步日期,默认为昨天"),
|
||||||
|
advertiser_id: Optional[str] = Query(None, description="指定广告主ID,不指定则同步所有授权的广告主"),
|
||||||
current_user: User = Depends(get_current_user),
|
current_user: User = Depends(get_current_user),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
) -> Any | dict:
|
) -> Any | dict:
|
||||||
if date is None:
|
if date is None:
|
||||||
date = (datetime.now(timezone.utc) - timedelta(days=1)).strftime("%Y-%m-%d")
|
date = (datetime.now(timezone.utc) - timedelta(days=1)).strftime("%Y-%m-%d")
|
||||||
|
|
||||||
# 测试用,手动触发同步素材消耗任务
|
from app.services.material_consumption_queue import material_consumption_queue
|
||||||
result = await _fetch_and_save_consumption("0019eb9f130027c05b8", "1863675913228435", date)
|
|
||||||
return {
|
query = (
|
||||||
"code": 0,
|
select(UserOAuth.id, UserOAuthAccount.advertiser_id)
|
||||||
"message": result,
|
.join(UserOAuthAccount, UserOAuth.id == UserOAuthAccount.oauth_id)
|
||||||
}
|
.join(ResourcesMaterial, UserOAuthAccount.advertiser_id == ResourcesMaterial.advertiser_id)
|
||||||
result = await sync_all_advertisers_consumption(date)
|
.where(
|
||||||
|
UserOAuth.user_id == current_user.id,
|
||||||
|
UserOAuth.deleted_at.is_(None),
|
||||||
|
UserOAuthAccount.deleted_at.is_(None),
|
||||||
|
ResourcesMaterial.deleted_at.is_(None),
|
||||||
|
ResourcesMaterial.material_id.is_not_(None),
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
|
||||||
|
if advertiser_id:
|
||||||
|
query = query.where(UserOAuthAccount.advertiser_id == advertiser_id)
|
||||||
|
|
||||||
|
result = await db.execute(query)
|
||||||
|
oauth_advertiser_pairs = result.all()
|
||||||
|
|
||||||
|
if not oauth_advertiser_pairs:
|
||||||
|
return {
|
||||||
|
"code": 0,
|
||||||
|
"message": "没有找到可同步的广告主",
|
||||||
|
}
|
||||||
|
|
||||||
|
for oauth_id, adv_id in oauth_advertiser_pairs:
|
||||||
|
await material_consumption_queue.enqueue({
|
||||||
|
"oauth_id": oauth_id,
|
||||||
|
"advertiser_id": adv_id,
|
||||||
|
"date": date,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"code": 0,
|
"code": 0,
|
||||||
"message": result["message"],
|
"message": f"已将 {len(oauth_advertiser_pairs)} 个广告主的消耗更新任务加入队列",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -299,3 +209,46 @@ async def get_advertisers(
|
|||||||
"code": 0,
|
"code": 0,
|
||||||
"data": [{"advertiser_id": str(aid)} for aid in advertisers],
|
"data": [{"advertiser_id": str(aid)} for aid in advertisers],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/admin/list",
|
||||||
|
summary="管理员查询所有素材消耗列表",
|
||||||
|
description="管理员可查看系统中所有用户的素材消耗数据",
|
||||||
|
)
|
||||||
|
async def admin_consumption_list(
|
||||||
|
page: int = Query(1, ge=1, description="页码"),
|
||||||
|
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
||||||
|
advertiser_id: Optional[str] = Query(None, description="广告主ID筛选"),
|
||||||
|
user_id: Optional[str] = Query(None, description="用户ID筛选"),
|
||||||
|
consume_date: Optional[List[str]] = Query(None, description="消耗日期范围,格式: ['开始日期','结束日期']"),
|
||||||
|
current_user: User = Depends(get_admin_user),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
) -> Any | dict:
|
||||||
|
#需要判断管理员吗
|
||||||
|
if not current_user.is_admin:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="只有管理员才能查询所有素材消耗列表",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
consumptions, total = await get_consumption_list(
|
||||||
|
db=db,
|
||||||
|
page=page,
|
||||||
|
page_size=page_size,
|
||||||
|
advertiser_id=advertiser_id,
|
||||||
|
user_id=user_id,
|
||||||
|
consume_date=consume_date,
|
||||||
|
current_user=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"code": 0,
|
||||||
|
"data": format_consumption_response(consumptions, include_oauth_id=True),
|
||||||
|
"pagination": {
|
||||||
|
"page": page,
|
||||||
|
"page_size": page_size,
|
||||||
|
"total": total,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional, List
|
||||||
|
|
||||||
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
||||||
from sqlalchemy import select, func
|
from sqlalchemy import select, func
|
||||||
@@ -18,6 +18,37 @@ from app.utils.id_gen import generate_id
|
|||||||
router = APIRouter(prefix="/open-type", tags=["open-type"])
|
router = APIRouter(prefix="/open-type", tags=["open-type"])
|
||||||
|
|
||||||
|
|
||||||
|
# 公共接口 - 无需登录
|
||||||
|
@router.get(
|
||||||
|
"/open_type_all",
|
||||||
|
summary="查询所有开户方式",
|
||||||
|
description="查询所有开户方式,前端使用select框选择,无需登录",
|
||||||
|
dependencies=[],
|
||||||
|
)
|
||||||
|
async def get_open_type_public(
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
) -> Any | dict:
|
||||||
|
|
||||||
|
result = await db.execute(
|
||||||
|
select(OpenType).where(OpenType.deleted_at.is_(None))
|
||||||
|
)
|
||||||
|
open_types = result.scalars().all()
|
||||||
|
return {
|
||||||
|
"code": 0,
|
||||||
|
"message": "查询成功",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": ot.id,
|
||||||
|
"type_name": ot.type_name,
|
||||||
|
"open_type": ot.open_type,
|
||||||
|
"description": ot.description,
|
||||||
|
"thumb": ot.thumb,
|
||||||
|
}
|
||||||
|
for ot in open_types
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/list",
|
"/list",
|
||||||
summary="获取开户方式列表",
|
summary="获取开户方式列表",
|
||||||
@@ -83,7 +114,7 @@ async def get_open_type_list(
|
|||||||
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/{id}",
|
"/select/{id}",
|
||||||
summary="获取开户方式详情",
|
summary="获取开户方式详情",
|
||||||
description="根据ID获取开户方式详情",
|
description="根据ID获取开户方式详情",
|
||||||
response_model=OpenTypeResponse,
|
response_model=OpenTypeResponse,
|
||||||
@@ -120,7 +151,7 @@ async def get_open_type_detail(
|
|||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
"/",
|
"/create",
|
||||||
summary="创建开户方式",
|
summary="创建开户方式",
|
||||||
description="创建新的开户方式",
|
description="创建新的开户方式",
|
||||||
response_model=OpenTypeResponse,
|
response_model=OpenTypeResponse,
|
||||||
@@ -167,7 +198,7 @@ async def create_open_type(
|
|||||||
|
|
||||||
|
|
||||||
@router.put(
|
@router.put(
|
||||||
"/{id}",
|
"/update/{id}",
|
||||||
summary="更新开户方式",
|
summary="更新开户方式",
|
||||||
description="更新指定的开户方式",
|
description="更新指定的开户方式",
|
||||||
response_model=OpenTypeResponse,
|
response_model=OpenTypeResponse,
|
||||||
@@ -231,7 +262,7 @@ async def update_open_type(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete(
|
@router.delete(
|
||||||
"/{id}",
|
"/delete/{id}",
|
||||||
summary="删除开户方式",
|
summary="删除开户方式",
|
||||||
description="软删除指定的开户方式",
|
description="软删除指定的开户方式",
|
||||||
response_model=OpenTypeResponse,
|
response_model=OpenTypeResponse,
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
from typing import Any, Optional, Tuple, List
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sqlalchemy import select, func
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.models.user import User
|
||||||
|
from app.models.material_cost import MaterialCost
|
||||||
|
from app.models.user_oauth import UserOAuth
|
||||||
|
|
||||||
|
|
||||||
|
async def get_consumption_list(
|
||||||
|
db: AsyncSession,
|
||||||
|
page: int = 1,
|
||||||
|
page_size: int = 20,
|
||||||
|
advertiser_id: Optional[str] = None,
|
||||||
|
user_id: Optional[str] = None,
|
||||||
|
consume_date: Optional[List[str]] = None,
|
||||||
|
current_user: Optional[User] = None,
|
||||||
|
) -> Tuple[List[MaterialCost], int]:
|
||||||
|
offset = (page - 1) * page_size
|
||||||
|
|
||||||
|
query = select(MaterialCost).where(MaterialCost.deleted_at.is_(None))
|
||||||
|
|
||||||
|
if current_user:
|
||||||
|
query = query.join(
|
||||||
|
UserOAuth,
|
||||||
|
MaterialCost.oauth_id == UserOAuth.id,
|
||||||
|
).where(
|
||||||
|
UserOAuth.user_id == current_user.id,
|
||||||
|
UserOAuth.deleted_at.is_(None),
|
||||||
|
)
|
||||||
|
|
||||||
|
if user_id:
|
||||||
|
query = query.join(
|
||||||
|
UserOAuth,
|
||||||
|
MaterialCost.oauth_id == UserOAuth.id,
|
||||||
|
).where(UserOAuth.user_id == user_id)
|
||||||
|
|
||||||
|
if advertiser_id:
|
||||||
|
query = query.where(MaterialCost.advertiser_id == advertiser_id)
|
||||||
|
|
||||||
|
if consume_date and len(consume_date) >= 2:
|
||||||
|
start_date_obj = datetime.strptime(consume_date[0], "%Y-%m-%d").date()
|
||||||
|
end_date_obj = datetime.strptime(consume_date[1], "%Y-%m-%d").date()
|
||||||
|
query = query.where(MaterialCost.consume_date >= start_date_obj)
|
||||||
|
query = query.where(MaterialCost.consume_date <= end_date_obj)
|
||||||
|
|
||||||
|
result = await db.execute(
|
||||||
|
query.order_by(MaterialCost.consume_date.desc())
|
||||||
|
.offset(offset)
|
||||||
|
.limit(page_size)
|
||||||
|
)
|
||||||
|
consumptions = result.scalars().all()
|
||||||
|
|
||||||
|
count_query = select(func.count(MaterialCost.id)).where(MaterialCost.deleted_at.is_(None))
|
||||||
|
|
||||||
|
if current_user:
|
||||||
|
count_query = count_query.join(
|
||||||
|
UserOAuth,
|
||||||
|
MaterialCost.oauth_id == UserOAuth.id,
|
||||||
|
).where(
|
||||||
|
UserOAuth.user_id == current_user.id,
|
||||||
|
UserOAuth.deleted_at.is_(None),
|
||||||
|
)
|
||||||
|
|
||||||
|
if user_id:
|
||||||
|
count_query = count_query.join(
|
||||||
|
UserOAuth,
|
||||||
|
MaterialCost.oauth_id == UserOAuth.id,
|
||||||
|
).where(UserOAuth.user_id == user_id)
|
||||||
|
|
||||||
|
if advertiser_id:
|
||||||
|
count_query = count_query.where(MaterialCost.advertiser_id == advertiser_id)
|
||||||
|
|
||||||
|
if consume_date and len(consume_date) >= 2:
|
||||||
|
start_date_obj = datetime.strptime(consume_date[0], "%Y-%m-%d").date()
|
||||||
|
end_date_obj = datetime.strptime(consume_date[1], "%Y-%m-%d").date()
|
||||||
|
count_query = count_query.where(MaterialCost.consume_date >= start_date_obj)
|
||||||
|
count_query = count_query.where(MaterialCost.consume_date <= end_date_obj)
|
||||||
|
|
||||||
|
total_result = await db.execute(count_query)
|
||||||
|
total = total_result.scalar_one()
|
||||||
|
|
||||||
|
return consumptions, total
|
||||||
|
|
||||||
|
|
||||||
|
def format_consumption_response(consumptions: List[MaterialCost], include_oauth_id: bool = False) -> List[dict]:
|
||||||
|
result = []
|
||||||
|
for consumption in consumptions:
|
||||||
|
item = {
|
||||||
|
"id": consumption.id,
|
||||||
|
"advertiser_id": consumption.advertiser_id,
|
||||||
|
"material_id": consumption.material_id,
|
||||||
|
"consume_date": consumption.consume_date.isoformat() if consumption.consume_date else None,
|
||||||
|
"stat_cost": consumption.stat_cost,
|
||||||
|
"show_cnt": consumption.show_cnt,
|
||||||
|
"cpm_platform": consumption.cpm_platform,
|
||||||
|
"click_cnt": consumption.click_cnt,
|
||||||
|
"ctr": consumption.ctr,
|
||||||
|
"cpc_platform": consumption.cpc_platform,
|
||||||
|
"convert_cnt": consumption.convert_cnt,
|
||||||
|
"conversion_cost": consumption.conversion_cost,
|
||||||
|
"conversion_rate": consumption.conversion_rate,
|
||||||
|
"deep_convert_cnt": consumption.deep_convert_cnt,
|
||||||
|
"deep_convert_cost": consumption.deep_convert_cost,
|
||||||
|
"deep_convert_rate": consumption.deep_convert_rate,
|
||||||
|
"active": consumption.active,
|
||||||
|
"active_cost": consumption.active_cost,
|
||||||
|
"active_rate": consumption.active_rate,
|
||||||
|
"active_register": consumption.active_register,
|
||||||
|
"active_register_cost": consumption.active_register_cost,
|
||||||
|
"active_register_rate": consumption.active_register_rate,
|
||||||
|
"attribution_next_day_open_cnt": consumption.attribution_next_day_open_cnt,
|
||||||
|
"attribution_next_day_open_cost": consumption.attribution_next_day_open_cost,
|
||||||
|
"attribution_next_day_open_rate": consumption.attribution_next_day_open_rate,
|
||||||
|
"active_pay": consumption.active_pay,
|
||||||
|
"active_pay_cost": consumption.active_pay_cost,
|
||||||
|
"active_pay_rate": consumption.active_pay_rate,
|
||||||
|
"phone": consumption.phone,
|
||||||
|
"form": consumption.form,
|
||||||
|
"download_start": consumption.download_start,
|
||||||
|
"form_submit": consumption.form_submit,
|
||||||
|
"button": consumption.button,
|
||||||
|
"view": consumption.view,
|
||||||
|
"message": consumption.message,
|
||||||
|
"consult": consumption.consult,
|
||||||
|
"consult_effective": consumption.consult_effective,
|
||||||
|
"shopping": consumption.shopping,
|
||||||
|
"customer_effective": consumption.customer_effective,
|
||||||
|
"attribution_game_in_app_ltv_1day": consumption.attribution_game_in_app_ltv_1day,
|
||||||
|
"attribution_game_in_app_roi_1day": consumption.attribution_game_in_app_roi_1day,
|
||||||
|
"loan_completion": consumption.loan_completion,
|
||||||
|
"loan_completion_cost": consumption.loan_completion_cost,
|
||||||
|
"loan_completion_rate": consumption.loan_completion_rate,
|
||||||
|
"loan_credit": consumption.loan_credit,
|
||||||
|
"loan_credit_cost": consumption.loan_credit_cost,
|
||||||
|
"loan_credit_rate": consumption.loan_credit_rate,
|
||||||
|
"in_app_order_gmv": consumption.in_app_order_gmv,
|
||||||
|
"in_app_order_roi": consumption.in_app_order_roi,
|
||||||
|
"in_app_pay_gmv": consumption.in_app_pay_gmv,
|
||||||
|
"in_app_pay_roi": consumption.in_app_pay_roi,
|
||||||
|
"total_play": consumption.total_play,
|
||||||
|
"valid_play": consumption.valid_play,
|
||||||
|
"valid_play_cost": consumption.valid_play_cost,
|
||||||
|
"valid_play_rate": consumption.valid_play_rate,
|
||||||
|
"valid_play_of_mille": consumption.valid_play_of_mille,
|
||||||
|
"valid_play_cost_of_mille": consumption.valid_play_cost_of_mille,
|
||||||
|
"average_play_time_per_play": consumption.average_play_time_per_play,
|
||||||
|
"play_over_rate": consumption.play_over_rate,
|
||||||
|
"dy_like": consumption.dy_like,
|
||||||
|
"dy_comment": consumption.dy_comment,
|
||||||
|
"dy_share": consumption.dy_share,
|
||||||
|
"report_cnt": consumption.report_cnt,
|
||||||
|
"created_at": consumption.created_at,
|
||||||
|
}
|
||||||
|
if include_oauth_id:
|
||||||
|
item["oauth_id"] = consumption.oauth_id
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
Reference in New Issue
Block a user