Files
SMANAGE/gvsds/apps/payment/views.py
T
TermiNexus cd9ebcddd1 "refactor(gerp): P0 鉴权链路委托 gvsdsdk 并清理死代码
role_scope 数据权限底座、form_service 默认角色/租户管理员/删用户/审计
改经 SDK;ugm/payment/stats 裸查询委托;删除 commission/payment/stats
冗余 manager/engine;修复 user_detail 潜伏 ImportError。"
2026-08-07 18:10:45 +08:00

195 lines
7.4 KiB
Python

import logging
from rest_framework.views import APIView
from rest_framework.response import Response
from gvsdsdk.payment.manager import PaymentManager, PaymentError
from gvsds.apps.payment.serializers import (
GatewayConfigCreateSerializer,
GatewayConfigSerializer,
PaymentRequestSerializer,
RefundRequestSerializer,
TransferRequestSerializer,
TransactionSerializer,
)
from gvsdsdk.payment.gateways.registry import payment_registry
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 GatewayConfigView(APIView):
def get(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
configs = PaymentManager(tenant).ListConfigs(status=1)
data = GatewayConfigSerializer(configs, many=True).data
return Response(_ok(data))
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = GatewayConfigCreateSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
manager = PaymentManager(tenant)
config = manager.ConfigureGateway(
platform=ser.ValidatedData['Platform'],
app_id=ser.ValidatedData.get('AppID', ''),
mch_id=ser.ValidatedData.get('MchID', ''),
api_key=ser.ValidatedData.get('APIKeyEncrypted', ''),
private_key=ser.ValidatedData.get('PrivateKeyEncrypted', ''),
public_key=ser.ValidatedData.get('PublicKeyEncrypted', ''),
cert_path=ser.ValidatedData.get('CertPath', ''),
cert_key_path=ser.ValidatedData.get('CertKeyPath', ''),
notify_url=ser.ValidatedData.get('NotifyURL', ''),
return_url=ser.ValidatedData.get('ReturnURL', ''),
extra=ser.ValidatedData.get('ConfigExtra', {}),
set_default=ser.ValidatedData.get('SetDefault', False),
)
return Response(_ok(GatewayConfigSerializer(config).data), status=201)
def delete(self, request):
tenant = _get_tenant(request)
platform = request.data.get('Platform')
if not tenant or not platform:
return Response(_err('缺少租户或平台', 400), status=400)
manager = PaymentManager(tenant)
manager.DisableConfig(platform)
return Response(_ok(msg='配置已禁用'))
class PayView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = PaymentRequestSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
manager = PaymentManager(tenant)
try:
tx = manager.Pay(
platform=ser.ValidatedData['Platform'],
amount=ser.ValidatedData['Amount'],
subject=ser.ValidatedData.get('Subject', ''),
body=ser.ValidatedData.get('Body', ''),
method=ser.ValidatedData.get('Method', 'jsapi'),
open_id=ser.ValidatedData.get('OpenID', ''),
client_ip=ser.ValidatedData.get('ClientIP', ''),
extra=ser.ValidatedData.get('Extra', {}),
expire_minutes=ser.ValidatedData.get('ExpireMinutes', 30),
)
except PaymentError as e:
return Response(_err(str(e), 400), status=400)
data = TransactionSerializer(tx).data
data['prepay_info'] = getattr(tx, '_prepay_info', {})
return Response(_ok(data), status=201)
class QueryView(APIView):
def get(self, request, out_trade_no):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
manager = PaymentManager(tenant)
try:
result = manager.Query(out_trade_no)
except PaymentError as e:
return Response(_err(str(e), 404), status=404)
return Response(_ok({
'success': result.Success,
'out_trade_no': result.OutTradeNO,
'transaction_id': result.TransactionID,
'trade_state': result.TradeState,
'trade_state_desc': result.TradeStateDesc,
'total_amount': str(result.TotalAmount),
}))
class RefundView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = RefundRequestSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
manager = PaymentManager(tenant)
try:
tx = manager.Refund(
out_trade_no=ser.ValidatedData['OutTradeNO'],
amount=ser.ValidatedData['Amount'],
reason=ser.ValidatedData.get('Reason', ''),
platform=ser.ValidatedData.get('Platform'),
extra=ser.ValidatedData.get('Extra', {}),
)
except PaymentError as e:
return Response(_err(str(e), 400), status=400)
return Response(_ok(TransactionSerializer(tx).data), status=201)
class TransferView(APIView):
def post(self, request):
tenant = _get_tenant(request)
if not tenant:
return Response(_err('缺少租户标识', 401), status=401)
ser = TransferRequestSerializer(data=request.data)
if not ser.IsValid():
return Response(_err(ser.errors, 400), status=400)
manager = PaymentManager(tenant)
try:
tx = manager.Transfer(
platform=ser.ValidatedData['Platform'],
amount=ser.ValidatedData['Amount'],
payee_account=ser.ValidatedData.get('PayeeAccount', ''),
payee_name=ser.ValidatedData.get('PayeeName', ''),
description=ser.ValidatedData.get('Description', ''),
transfer_type=ser.ValidatedData.get('TransferType', 'wallet'),
extra=ser.ValidatedData.get('Extra', {}),
)
except PaymentError as e:
return Response(_err(str(e), 400), status=400)
return Response(_ok(TransactionSerializer(tx).data), status=201)
class NotifyView(APIView):
authentication_classes = []
permission_classes = []
def post(self, request, platform):
tenant = request.headers.get('X-Tenant-UUID', '')
if not tenant:
return Response(_err('缺少租户标识', 400), status=400)
headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')}
manager = PaymentManager(tenant)
tx = manager.HandleNotify(
platform=platform,
raw_data=request.body,
headers=headers,
)
if tx is None:
return Response(_err('回调处理失败', 400), status=400)
return Response(_ok(TransactionSerializer(tx).data))
class ChannelListView(APIView):
def get(self, request):
return Response(_ok(payment_registry.list_all_info()))