refactor: 更新权限管理与请求验证逻辑
- 在多个控制器中将权限检查从 hasAdminPermission 更新为 hasPermissionCode,以增强权限管理的灵活性。 - 引入 AdminScopePolicy,优化基于代理节点的权限和数据过滤逻辑,确保管理员能够更精确地控制访问权限。 - 在请求验证中添加 agent_node_id 字段,确保 API 接口支持代理节点的相关操作。 - 更新 AdminUser 模型,新增 hasPermissionCode 方法,以支持更细粒度的权限检查。 - 优化审计日志记录逻辑,确保在处理请求时能够准确记录管理员的操作。
This commit is contained in:
@@ -7,9 +7,10 @@ use App\Support\ApiResponse;
|
||||
use App\Models\TransferOrder;
|
||||
use App\Support\PaginationTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Support\AdminSiteScope;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use App\Support\AgentNodeApiPresenter;
|
||||
use App\Support\CurrencyFormatter;
|
||||
use App\Services\Wallet\LotteryTransferService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\TransferOrderListRequest;
|
||||
|
||||
@@ -34,12 +35,17 @@ final class TransferOrderListController extends Controller
|
||||
|
||||
private const ALLOWED_STATUS = ['processing', 'success', 'failed', 'pending_reconcile', 'reversed', 'manually_processed'];
|
||||
|
||||
public function __construct(
|
||||
private readonly LotteryTransferService $transferService,
|
||||
) {}
|
||||
|
||||
public function __invoke(TransferOrderListRequest $request): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$validated = $request->validated();
|
||||
$scope = AdminScopePolicy::resolveContext($request, $admin);
|
||||
|
||||
$perPage = $this->perPage($request, 'per_page', 10, 100);
|
||||
$page = $this->page($request);
|
||||
@@ -89,15 +95,7 @@ final class TransferOrderListController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$agentNodeId = isset($validated['agent_node_id']) ? (int) $validated['agent_node_id'] : null;
|
||||
|
||||
AdminSiteScope::applyViaPlayerRelationWithSiteCode(
|
||||
$query,
|
||||
$admin,
|
||||
is_string($validated['site_code'] ?? null) ? $validated['site_code'] : null,
|
||||
'player',
|
||||
$agentNodeId > 0 ? $agentNodeId : null,
|
||||
);
|
||||
AdminScopePolicy::applyViaPlayerRelationWithContext($query, $scope, 'player');
|
||||
|
||||
$paginator = $query->paginate($perPage, ['*'], 'page', $page);
|
||||
$items = $paginator->getCollection()->map(
|
||||
@@ -120,8 +118,9 @@ final class TransferOrderListController extends Controller
|
||||
$p = $o->player;
|
||||
$amount = (int) $o->amount;
|
||||
$canWriteWallet = $admin !== null && (
|
||||
$admin->hasAdminPermission('prd.wallet_adjust.manage')
|
||||
|| $admin->hasAdminPermission('prd.wallet_reconcile.manage')
|
||||
$admin->hasPermissionCode('service.wallet.adjust')
|
||||
|| $admin->hasPermissionCode('service.reconcile.manage')
|
||||
|| $admin->hasPermissionCode('service.wallet.manage')
|
||||
);
|
||||
|
||||
return [
|
||||
@@ -139,15 +138,16 @@ final class TransferOrderListController extends Controller
|
||||
'amount_formatted' => CurrencyFormatter::fromMinor($amount),
|
||||
'idempotent_key' => $o->idempotent_key,
|
||||
'status' => $o->status,
|
||||
'can_reverse' => $canWriteWallet && $o->status === 'pending_reconcile',
|
||||
'can_reverse' => $canWriteWallet
|
||||
&& $o->status === 'pending_reconcile'
|
||||
&& ($o->direction === 'out' || $this->transferService->isEligibleForTransferInReverse($o)),
|
||||
'can_complete_credit' => $canWriteWallet
|
||||
&& $o->direction === 'in'
|
||||
&& $o->status === 'pending_reconcile'
|
||||
&& $o->fail_reason === 'lottery_credit_failed'
|
||||
&& trim((string) $o->external_ref_no) !== '',
|
||||
'can_manually_process' => $canWriteWallet
|
||||
&& in_array($o->status, ['processing', 'failed', 'pending_reconcile'], true)
|
||||
&& ! ($o->direction === 'out' && $o->status === 'pending_reconcile'),
|
||||
&& $this->transferService->isEligibleForManualProcess($o),
|
||||
'external_ref_no' => $o->external_ref_no,
|
||||
'external_request_payload' => $o->external_request_payload,
|
||||
'external_response_payload' => $o->external_response_payload,
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Lottery\ErrorCode;
|
||||
use App\Models\TransferOrder;
|
||||
use App\Support\ApiMessage;
|
||||
use App\Support\ApiResponse;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use App\Support\LotteryMessage;
|
||||
use App\Exceptions\WalletOperationException;
|
||||
use App\Services\Wallet\LotteryTransferService;
|
||||
@@ -16,8 +17,8 @@ use App\Http\Requests\Admin\Wallet\TransferOrderCompleteCreditRequest;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* 后台:转账订单对账操作(冲正 / 人工处理)。
|
||||
* PRD §12:待对账 -> 已冲正 / 已人工处理。
|
||||
* 后台:转账订单对账操作(冲正 / 补入账 / 标记结案)。
|
||||
* PRD §12:待对账 -> 已冲正 / 已结案(manually_processed,仅改状态)。
|
||||
*/
|
||||
final class TransferOrderReconcileController extends Controller
|
||||
{
|
||||
@@ -27,10 +28,16 @@ final class TransferOrderReconcileController extends Controller
|
||||
|
||||
public function reverse(TransferOrderReverseRequest $request, string $transferNo): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$order = TransferOrder::query()->where('transfer_no', $transferNo)->first();
|
||||
if ($order === null) {
|
||||
return ApiMessage::errorResponse($request, 'wallet.order_not_found', ErrorCode::ClientHttpError->value, null, 404);
|
||||
}
|
||||
if (! AdminScopePolicy::transferOrderAccessible($admin, $order)) {
|
||||
return ApiMessage::errorResponse($request, 'admin.site_player_access_denied', ErrorCode::AdminForbidden->value, null, 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->transferService->reconcileTransferOrder(
|
||||
@@ -52,10 +59,16 @@ final class TransferOrderReconcileController extends Controller
|
||||
|
||||
public function manuallyProcess(TransferOrderManuallyProcessRequest $request, string $transferNo): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$order = TransferOrder::query()->where('transfer_no', $transferNo)->first();
|
||||
if ($order === null) {
|
||||
return ApiMessage::errorResponse($request, 'wallet.order_not_found', ErrorCode::ClientHttpError->value, null, 404);
|
||||
}
|
||||
if (! AdminScopePolicy::transferOrderAccessible($admin, $order)) {
|
||||
return ApiMessage::errorResponse($request, 'admin.site_player_access_denied', ErrorCode::AdminForbidden->value, null, 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->transferService->reconcileTransferOrder(
|
||||
@@ -77,10 +90,16 @@ final class TransferOrderReconcileController extends Controller
|
||||
|
||||
public function completeCredit(TransferOrderCompleteCreditRequest $request, string $transferNo): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$order = TransferOrder::query()->where('transfer_no', $transferNo)->first();
|
||||
if ($order === null) {
|
||||
return ApiMessage::errorResponse($request, 'wallet.order_not_found', ErrorCode::ClientHttpError->value, null, 404);
|
||||
}
|
||||
if (! AdminScopePolicy::transferOrderAccessible($admin, $order)) {
|
||||
return ApiMessage::errorResponse($request, 'admin.site_player_access_denied', ErrorCode::AdminForbidden->value, null, 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->transferService->reconcileTransferOrder(
|
||||
|
||||
@@ -6,7 +6,7 @@ use App\Models\WalletTxn;
|
||||
use App\Support\ApiResponse;
|
||||
use App\Support\PaginationTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Support\AdminSiteScope;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use App\Support\AgentNodeApiPresenter;
|
||||
use App\Support\CurrencyFormatter;
|
||||
use App\Http\Controllers\Controller;
|
||||
@@ -39,6 +39,7 @@ final class WalletTransactionListController extends Controller
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$validated = $request->validated();
|
||||
$scope = AdminScopePolicy::resolveContext($request, $admin);
|
||||
|
||||
$perPage = $this->perPage($request, 'per_page', 10, 100);
|
||||
$page = $this->page($request);
|
||||
@@ -92,15 +93,7 @@ final class WalletTransactionListController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$agentNodeId = isset($validated['agent_node_id']) ? (int) $validated['agent_node_id'] : null;
|
||||
|
||||
AdminSiteScope::applyViaPlayerRelationWithSiteCode(
|
||||
$query,
|
||||
$admin,
|
||||
is_string($validated['site_code'] ?? null) ? $validated['site_code'] : null,
|
||||
'player',
|
||||
$agentNodeId > 0 ? $agentNodeId : null,
|
||||
);
|
||||
AdminScopePolicy::applyViaPlayerRelationWithContext($query, $scope, 'player');
|
||||
|
||||
$paginator = $query->paginate($perPage, ['*'], 'page', $page);
|
||||
$items = $paginator->getCollection()->map(fn (WalletTxn $t) => $this->formatRow($t));
|
||||
|
||||
Reference in New Issue
Block a user