Files
TermiNexus 7d578f82a4 "refactor(views): route commission/payment config views through gvsdsdk
- commission rule/rate-table/event endpoints use CommissionEngine
- payment gateway config list/detail/save/delete use PaymentManager
- remove unused model imports"
2026-08-07 02:26:35 +08:00

260 lines
10 KiB
Python

import logging
from rest_framework.views import APIView
from rest_framework.response import Response
from gvsdsdk.commission.manager import CommissionEngine, CommissionError
from gvsds.apps.commission.serializers import (
DispatchRequestSerializer,
RuleCreateSerializer,
RateTableCreateSerializer,
CommissionRuleSerializer,
CommissionRecordSerializer,
RateTableSerializer,
CommissionEventSerializer,
PreSettleRequestSerializer,
PreSettleConfirmSerializer,
FeeCalcSerializer,
InviteChainDispatchSerializer,
)
from gvsdsdk.commission.models import CommissionEvent
logger = logging.getLogger(__name__)
def _ok(data=None, msg='success'):
return {'code': 200, 'msg': msg, 'data': data}
def _err(msg, code=400):
return {'code': code, 'msg': msg, 'data': None}
def _get_tenant(request):
return request.headers.get('X-Tenant-UUID', '') or getattr(request, 'tenant_uuid', '')
class RuleConfigView(APIView):
def get(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
EventType = request.query_params.get('EventType', '')
engine = CommissionEngine(tenant)
qs = engine.ListRules(EventType or None)
return Response(_ok(CommissionRuleSerializer(qs, many=True).data))
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = RuleCreateSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
rule = engine.ConfigureRule(
event_type=ser.ValidatedData['EventType'],
rule_name=ser.ValidatedData['RuleName'],
participant_rules=ser.ValidatedData['ParticipantRules'],
rule_description=ser.ValidatedData.get('RuleDescription', ''),
max_invite_level=ser.ValidatedData.get('MaxInviteLevel', 2),
rate_table_uuid=ser.ValidatedData.get('RateTableUUID', ''),
rule_priority=ser.ValidatedData.get('RulePriority', 0),
)
return Response(_ok(CommissionRuleSerializer(rule).data), status=201)
def delete(self, request):
tenant = _get_tenant(request)
rule_uuid = request.data.get('RuleUUID')
if not tenant or not rule_uuid:
return Response(_err('缺少参数', 400), status=400)
engine = CommissionEngine(tenant)
engine.DisableRule(rule_uuid)
return Response(_ok(msg='规则已禁用'))
class RateTableView(APIView):
def get(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
engine = CommissionEngine(tenant)
tables = engine.ListRateTables()
return Response(_ok(RateTableSerializer(tables, many=True).data))
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = RateTableCreateSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
table = engine.ConfigureRateTable(
table_code=ser.ValidatedData['TableCode'],
table_name=ser.ValidatedData['TableName'],
entries=ser.ValidatedData['Entries'],
table_description=ser.ValidatedData.get('TableDescription', ''),
)
return Response(_ok(RateTableSerializer(table).data), status=201)
class DispatchView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = DispatchRequestSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
try:
records = engine.Dispatch(
event_type=ser.ValidatedData['EventType'],
event_key=ser.ValidatedData['EventKey'],
total_amount=ser.ValidatedData['TotalAmount'],
source_user_uuid=ser.ValidatedData.get('SourceUserUUID', ''),
participants=ser.ValidatedData.get('Participants', {}),
tier_index=ser.ValidatedData.get('TierIndex', 0),
payload=ser.ValidatedData.get('Payload', {}),
auto_settle=ser.ValidatedData.get('AutoSettle', True),
)
except CommissionError as e:
return Response(_err(str(e), 400), status=400)
return Response(_ok(CommissionRecordSerializer(records, many=True).data), status=201)
class InviteChainDispatchView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = InviteChainDispatchSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
try:
records = engine.BuildInviteChainCommission(
event_type=ser.ValidatedData['EventType'],
event_key=ser.ValidatedData['EventKey'],
total_amount=ser.ValidatedData['TotalAmount'],
source_user_uuid=ser.ValidatedData['SourceUserUUID'],
invite_chain=ser.ValidatedData['InviteChain'],
rule_name=ser.ValidatedData['RuleName'],
participant_rules=ser.ValidatedData['ParticipantRules'],
)
except CommissionError as e:
return Response(_err(str(e), 400), status=400)
return Response(_ok(CommissionRecordSerializer(records, many=True).data), status=201)
class QueryView(APIView):
def get(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
engine = CommissionEngine(tenant)
records = engine.QueryRecords(
participant_id=request.query_params.get('ParticipantID', ''),
event_type=request.query_params.get('EventType', ''),
status=request.query_params.get('Status'),
start_date=request.query_params.get('StartDate'),
end_date=request.query_params.get('EndDate'),
limit=int(request.query_params.get('Limit', 50)),
)
return Response(_ok(CommissionRecordSerializer(records, many=True).data))
class TotalView(APIView):
def get(self, request, participant_id):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
engine = CommissionEngine(tenant)
total = engine.TotalByParticipant(
participant_id=participant_id,
start_date=request.query_params.get('StartDate'),
end_date=request.query_params.get('EndDate'),
)
return Response(_ok({'participant_id': participant_id, 'total_amount': str(total)}))
class FeeCalcView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = FeeCalcSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
fee = engine.CalculateFee(
total_amount=ser.ValidatedData['TotalAmount'],
rate_table_code=ser.ValidatedData['RateTableCode'],
rate_key=ser.ValidatedData['RateKey'],
)
return Response(_ok({
'TotalAmount': str(ser.ValidatedData['TotalAmount']),
'Fee': str(fee),
'NetAmount': str(ser.ValidatedData['TotalAmount'] - fee),
}))
class PreSettleView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = PreSettleRequestSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
ps = engine.PreSettle(
event_key=ser.ValidatedData['EventKey'],
external_platform=ser.ValidatedData['ExternalPlatform'],
external_order_id=ser.ValidatedData['ExternalOrderID'],
participant_id=ser.ValidatedData['ParticipantID'],
amount=ser.ValidatedData['Amount'],
order_amount=ser.ValidatedData.get('OrderAmount', 0),
participant_role=ser.ValidatedData.get('ParticipantRole', 'worker'),
confirm_deadline=ser.ValidatedData.get('ConfirmDeadline'),
)
return Response(_ok({'settlement_uuid': str(ps.SettlementUUID)}), status=201)
class PreSettleConfirmView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = PreSettleConfirmSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
engine = CommissionEngine(tenant)
engine.ConfirmPreSettlement(
event_key=ser.ValidatedData['EventKey'],
participant_id=ser.ValidatedData.get('ParticipantID', ''),
confirmed_by=ser.ValidatedData.get('ConfirmedBy', ''),
)
return Response(_ok(msg='预结算已确认'))
class EventListView(APIView):
def get(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
engine = CommissionEngine(tenant)
qs = engine.ListEvents(
event_type=request.query_params.get('EventType', '') or None,
limit=int(request.query_params.get('Limit', 50)),
)
return Response(_ok(CommissionEventSerializer(qs, many=True).data))