203 lines
5.8 KiB
Python
203 lines
5.8 KiB
Python
import logging
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import outerjoin
|
|
from sqladmin import ModelView, action
|
|
from starlette.requests import Request
|
|
from starlette.responses import RedirectResponse
|
|
|
|
from app.backoffice.admin.models import Admin
|
|
from app.credit.models import CreditChargeRequest, CreditTransaction
|
|
from app.credit.services.credit_service import approve_charge_request, reject_charge_request
|
|
from app.database.session import AsyncSessionLocal
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CreditChargeRequestAdmin(ModelView, model=CreditChargeRequest):
|
|
name = "충전 요청"
|
|
name_plural = "충전 요청 목록"
|
|
icon = "fa-solid fa-coins"
|
|
category = "크레딧 관리"
|
|
page_size = 20
|
|
|
|
column_list = [
|
|
"id",
|
|
"user_uuid",
|
|
"requested_amount",
|
|
"status",
|
|
"admin.name",
|
|
"processed_at",
|
|
"created_at",
|
|
]
|
|
|
|
column_details_list = [
|
|
"id",
|
|
"user_uuid",
|
|
"requested_amount",
|
|
"message",
|
|
"status",
|
|
"admin.name",
|
|
"admin_note",
|
|
"processed_at",
|
|
"created_at",
|
|
"updated_at",
|
|
]
|
|
|
|
form_columns = ["admin_note"]
|
|
|
|
can_create = False
|
|
|
|
column_searchable_list = [
|
|
CreditChargeRequest.user_uuid,
|
|
CreditChargeRequest.status,
|
|
]
|
|
|
|
column_default_sort = (CreditChargeRequest.created_at, True)
|
|
|
|
column_sortable_list = [
|
|
CreditChargeRequest.id,
|
|
CreditChargeRequest.user_uuid,
|
|
CreditChargeRequest.requested_amount,
|
|
CreditChargeRequest.status,
|
|
CreditChargeRequest.processed_at,
|
|
CreditChargeRequest.created_at,
|
|
]
|
|
|
|
column_labels = {
|
|
"id": "ID",
|
|
"user_uuid": "사용자 UUID",
|
|
"requested_amount": "요청 크레딧",
|
|
"message": "사용자 메시지",
|
|
"status": "상태",
|
|
"admin.name": "처리 관리자",
|
|
"admin_note": "관리자 메모",
|
|
"processed_at": "처리일시",
|
|
"created_at": "요청일시",
|
|
"updated_at": "수정일시",
|
|
}
|
|
|
|
@action(
|
|
name="approve_request",
|
|
label="승인",
|
|
confirmation_message="선택한 충전 요청을 승인하시겠습니까?",
|
|
add_in_detail=True,
|
|
add_in_list=True,
|
|
)
|
|
async def approve_action(self, request: Request) -> RedirectResponse:
|
|
admin_id = request.session.get("admin_id")
|
|
pks = request.query_params.get("pks", "")
|
|
|
|
async with AsyncSessionLocal() as session:
|
|
for pk in pks.split(","):
|
|
if not pk.strip():
|
|
continue
|
|
try:
|
|
await approve_charge_request(
|
|
session=session,
|
|
request_id=int(pk),
|
|
admin_id=admin_id,
|
|
)
|
|
await session.commit()
|
|
except Exception as e:
|
|
await session.rollback()
|
|
logger.warning(f"[CREDIT-ADMIN] approve failed request_id={pk} error={e}")
|
|
|
|
return RedirectResponse(request.url_for("admin:list", identity=self.identity), status_code=302)
|
|
|
|
@action(
|
|
name="reject_request",
|
|
label="반려",
|
|
confirmation_message="선택한 충전 요청을 반려하시겠습니까?",
|
|
add_in_detail=True,
|
|
add_in_list=True,
|
|
)
|
|
async def reject_action(self, request: Request) -> RedirectResponse:
|
|
admin_id = request.session.get("admin_id")
|
|
pks = request.query_params.get("pks", "")
|
|
|
|
async with AsyncSessionLocal() as session:
|
|
for pk in pks.split(","):
|
|
if not pk.strip():
|
|
continue
|
|
try:
|
|
await reject_charge_request(
|
|
session=session,
|
|
request_id=int(pk),
|
|
admin_id=admin_id,
|
|
)
|
|
await session.commit()
|
|
except Exception as e:
|
|
await session.rollback()
|
|
logger.warning(f"[CREDIT-ADMIN] reject failed request_id={pk} error={e}")
|
|
|
|
return RedirectResponse(request.url_for("admin:list", identity=self.identity), status_code=302)
|
|
|
|
|
|
class CreditTransactionAdmin(ModelView, model=CreditTransaction):
|
|
name = "크레딧 변경"
|
|
name_plural = "크레딧 변경 목록"
|
|
icon = "fa-solid fa-clock-rotate-left"
|
|
category = "크레딧 관리"
|
|
page_size = 50
|
|
|
|
can_create = False
|
|
can_edit = False
|
|
can_delete = False
|
|
|
|
column_list = [
|
|
"id",
|
|
"user_uuid",
|
|
"amount",
|
|
"balance_after",
|
|
"type",
|
|
"admin.name",
|
|
"related_request_id",
|
|
"created_at",
|
|
]
|
|
|
|
column_details_list = [
|
|
"id",
|
|
"user_uuid",
|
|
"amount",
|
|
"balance_after",
|
|
"type",
|
|
"reason",
|
|
"admin.name",
|
|
"related_request_id",
|
|
"created_at",
|
|
]
|
|
|
|
column_searchable_list = [
|
|
CreditTransaction.user_uuid,
|
|
CreditTransaction.type,
|
|
]
|
|
|
|
column_default_sort = (CreditTransaction.created_at, True)
|
|
|
|
column_sortable_list = [
|
|
CreditTransaction.id,
|
|
CreditTransaction.user_uuid,
|
|
CreditTransaction.amount,
|
|
CreditTransaction.type,
|
|
CreditTransaction.created_at,
|
|
]
|
|
|
|
column_labels = {
|
|
"id": "ID",
|
|
"user_uuid": "사용자 UUID",
|
|
"amount": "변경 크레딧",
|
|
"balance_after": "변경 후 잔액",
|
|
"type": "변경 유형",
|
|
"reason": "사유",
|
|
"admin.name": "처리 관리자",
|
|
"related_request_id": "충전 요청 ID",
|
|
"created_at": "변경 일시",
|
|
}
|
|
|
|
def list_query(self, _request: Request):
|
|
return (
|
|
select(CreditTransaction)
|
|
.select_from(outerjoin(CreditTransaction, Admin, CreditTransaction.admin_id == Admin.id))
|
|
)
|