feat(risk): 支持按开注商隔离风险池并新增经营报表
This commit is contained in:
@@ -36,6 +36,7 @@ final class RiskCapItemsReplaceController extends Controller
|
||||
|
||||
$data = $request->validate([
|
||||
'items' => ['required', 'array', 'min:1'],
|
||||
'items.*.provider_code' => ['sometimes', 'string', 'max:32', 'regex:/^[A-Za-z0-9_-]+$/'],
|
||||
'items.*.draw_id' => ['sometimes', 'nullable', 'integer', 'exists:draws,id'],
|
||||
'items.*.normalized_number' => ['required', 'string', 'size:4', 'regex:/^[0-9]{4}$/'],
|
||||
'items.*.cap_amount' => ['required', 'integer', 'min:1'],
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Reports;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\AdminReportQueryRequest;
|
||||
use App\Services\Admin\AdminReportQueryService;
|
||||
use App\Support\AdminApiList;
|
||||
use App\Support\AdminScopePolicy;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/** GET /api/v1/admin/reports/provider-profit */
|
||||
final class AdminReportProviderProfitController extends Controller
|
||||
{
|
||||
public function __invoke(AdminReportQueryRequest $request, AdminReportQueryService $service): JsonResponse
|
||||
{
|
||||
$admin = $request->lotteryAdmin();
|
||||
abort_if($admin === null, 401);
|
||||
|
||||
$validated = $request->validated();
|
||||
$paging = AdminApiList::readPaging($request);
|
||||
$range = $service->resolveDateRange($validated);
|
||||
$scope = AdminScopePolicy::resolveContext($request, $admin, 'site_code', 'agent_node_id');
|
||||
$paginator = $service->providerProfitPaginated(
|
||||
$range['date_from'], $range['date_to'], $paging['page'], $paging['perPage'], $scope,
|
||||
);
|
||||
|
||||
return AdminApiList::jsonWith($paginator, static function (object $row): array {
|
||||
return [
|
||||
'provider_code' => (string) $row->provider_code,
|
||||
'provider_name' => (string) $row->provider_name,
|
||||
'ticket_item_count' => (int) $row->ticket_item_count,
|
||||
'total_bet_minor' => (int) $row->total_bet_minor,
|
||||
'total_payout_minor' => (int) $row->total_payout_minor,
|
||||
'approx_house_gross_minor' => (int) $row->approx_house_gross_minor,
|
||||
];
|
||||
}, [
|
||||
'currency_code' => $service->resolvePeriodCurrencyCode($range['date_from'], $range['date_to'], $scope),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
||||
|
||||
use App\Models\BetProvider;
|
||||
use App\Models\Draw;
|
||||
use App\Models\RiskPool;
|
||||
use App\Models\TicketOrder;
|
||||
@@ -25,9 +26,13 @@ final class AdminRiskPoolIndexController extends Controller
|
||||
$highRiskOnly = $request->boolean('high_risk_only');
|
||||
$activeOnly = $request->boolean('active_only');
|
||||
$number = trim((string) $request->query('normalized_number', ''));
|
||||
$providerCode = strtoupper(trim((string) $request->query('provider_code', '')));
|
||||
$sort = trim((string) $request->query('sort', 'usage_desc'));
|
||||
|
||||
$q = RiskPool::query()->where('draw_id', $draw->id);
|
||||
if ($providerCode !== '') {
|
||||
$q->where('provider_code', $providerCode);
|
||||
}
|
||||
|
||||
if ($soldOutOnly) {
|
||||
$q->where('sold_out_status', 1);
|
||||
@@ -47,11 +52,12 @@ final class AdminRiskPoolIndexController extends Controller
|
||||
}
|
||||
|
||||
match ($sort) {
|
||||
'locked_desc' => $q->orderByDesc('locked_amount')->orderBy('normalized_number'),
|
||||
'remaining_asc' => $q->orderBy('remaining_amount')->orderBy('normalized_number'),
|
||||
'number_asc' => $q->orderBy('normalized_number'),
|
||||
'locked_desc' => $q->orderByDesc('locked_amount')->orderBy('provider_code')->orderBy('normalized_number'),
|
||||
'remaining_asc' => $q->orderBy('remaining_amount')->orderBy('provider_code')->orderBy('normalized_number'),
|
||||
'number_asc' => $q->orderBy('provider_code')->orderBy('normalized_number'),
|
||||
default => $q->orderByRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) DESC')
|
||||
->orderByDesc('locked_amount')
|
||||
->orderBy('provider_code')
|
||||
->orderBy('normalized_number'),
|
||||
};
|
||||
|
||||
@@ -76,6 +82,7 @@ final class AdminRiskPoolIndexController extends Controller
|
||||
$locked = (int) $pool->locked_amount;
|
||||
|
||||
return [
|
||||
'provider_code' => $pool->provider_code ?? BetProvider::DEFAULT_CODE,
|
||||
'normalized_number' => $pool->normalized_number,
|
||||
'total_cap_amount' => $cap,
|
||||
'locked_amount' => $locked,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
||||
|
||||
use App\Models\BetProvider;
|
||||
use App\Models\Draw;
|
||||
use App\Models\TicketOrder;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -58,6 +59,7 @@ final class AdminRiskPoolLockLogIndexController extends Controller
|
||||
{
|
||||
return [
|
||||
'id' => (int) $log->id,
|
||||
'provider_code' => $log->provider_code ?? BetProvider::DEFAULT_CODE,
|
||||
'normalized_number' => $log->normalized_number,
|
||||
'action_type' => $log->action_type,
|
||||
'amount' => (int) $log->amount,
|
||||
@@ -76,6 +78,7 @@ final class AdminRiskPoolLockLogIndexController extends Controller
|
||||
$lastAt = $row->last_at ?? null;
|
||||
|
||||
return [
|
||||
'provider_code' => (string) ($row->provider_code ?? BetProvider::DEFAULT_CODE),
|
||||
'ticket_item_id' => (int) $row->ticket_item_id,
|
||||
'ticket_no' => (string) $row->ticket_no,
|
||||
'play_code' => (string) $row->play_code,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
||||
|
||||
use App\Models\BetProvider;
|
||||
use App\Models\Draw;
|
||||
use App\Models\RiskPool;
|
||||
use App\Lottery\ErrorCode;
|
||||
@@ -21,7 +22,8 @@ final class AdminRiskPoolManualStatusController extends Controller
|
||||
) {}
|
||||
public function close(Request $request, Draw $draw, string $number_4d): JsonResponse
|
||||
{
|
||||
$pool = $this->updateStatus($draw, $number_4d, true, 'close', 'admin_manual_close');
|
||||
$providerCode = strtoupper(trim((string) $request->query('provider_code', BetProvider::DEFAULT_CODE)));
|
||||
$pool = $this->updateStatus($draw, $providerCode, $number_4d, true, 'close', 'admin_manual_close');
|
||||
|
||||
if ($pool === null) {
|
||||
return ApiMessage::errorResponse($request, 'not_found', ErrorCode::ClientHttpError->value, null, 404);
|
||||
@@ -32,7 +34,8 @@ final class AdminRiskPoolManualStatusController extends Controller
|
||||
|
||||
public function recover(Request $request, Draw $draw, string $number_4d): JsonResponse
|
||||
{
|
||||
$pool = $this->updateStatus($draw, $number_4d, false, 'recover', 'admin_manual_recover');
|
||||
$providerCode = strtoupper(trim((string) $request->query('provider_code', BetProvider::DEFAULT_CODE)));
|
||||
$pool = $this->updateStatus($draw, $providerCode, $number_4d, false, 'recover', 'admin_manual_recover');
|
||||
|
||||
if ($pool === null) {
|
||||
return ApiMessage::errorResponse($request, 'not_found', ErrorCode::ClientHttpError->value, null, 404);
|
||||
@@ -48,14 +51,16 @@ final class AdminRiskPoolManualStatusController extends Controller
|
||||
|
||||
private function updateStatus(
|
||||
Draw $draw,
|
||||
string $providerCode,
|
||||
string $number4d,
|
||||
bool $soldOut,
|
||||
string $actionType,
|
||||
string $reason,
|
||||
): ?RiskPool {
|
||||
return DB::transaction(function () use ($draw, $number4d, $soldOut, $actionType, $reason): ?RiskPool {
|
||||
return DB::transaction(function () use ($draw, $providerCode, $number4d, $soldOut, $actionType, $reason): ?RiskPool {
|
||||
$pool = RiskPool::query()
|
||||
->where('draw_id', $draw->id)
|
||||
->where('provider_code', $providerCode)
|
||||
->where('normalized_number', $number4d)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
@@ -76,11 +81,12 @@ final class AdminRiskPoolManualStatusController extends Controller
|
||||
])->save();
|
||||
|
||||
if ($targetStatus === 1) {
|
||||
$this->riskPoolService->publishManualSoldOut($draw, $number4d);
|
||||
$this->riskPoolService->publishManualSoldOut($draw, $number4d, $providerCode);
|
||||
}
|
||||
|
||||
RiskPoolLockLog::query()->create([
|
||||
'draw_id' => $draw->id,
|
||||
'provider_code' => $providerCode,
|
||||
'normalized_number' => $number4d,
|
||||
'ticket_item_id' => null,
|
||||
'action_type' => $actionType,
|
||||
@@ -106,6 +112,7 @@ final class AdminRiskPoolManualStatusController extends Controller
|
||||
$locked = (int) $pool->locked_amount;
|
||||
|
||||
return [
|
||||
'provider_code' => $pool->provider_code ?? BetProvider::DEFAULT_CODE,
|
||||
'normalized_number' => $pool->normalized_number,
|
||||
'total_cap_amount' => $cap,
|
||||
'locked_amount' => $locked,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
||||
|
||||
use App\Models\BetProvider;
|
||||
use App\Models\Draw;
|
||||
use App\Models\RiskPool;
|
||||
use App\Lottery\ErrorCode;
|
||||
@@ -30,8 +31,11 @@ final class AdminRiskPoolShowController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
$providerCode = strtoupper(trim((string) $request->query('provider_code', BetProvider::DEFAULT_CODE)));
|
||||
|
||||
$pool = RiskPool::query()
|
||||
->where('draw_id', $draw->id)
|
||||
->where('provider_code', $providerCode)
|
||||
->where('normalized_number', $number_4d)
|
||||
->first();
|
||||
|
||||
@@ -49,6 +53,7 @@ final class AdminRiskPoolShowController extends Controller
|
||||
/** @var LengthAwarePaginator $paginator */
|
||||
$paginator = RiskPoolLockLog::query()
|
||||
->where('draw_id', $draw->id)
|
||||
->where('provider_code', $providerCode)
|
||||
->where('normalized_number', $number_4d)
|
||||
->with(['ticketItem:id,ticket_no,play_code,player_id'])
|
||||
->orderByDesc('created_at')
|
||||
@@ -66,6 +71,7 @@ final class AdminRiskPoolShowController extends Controller
|
||||
'draw_no' => $draw->draw_no,
|
||||
'currency_code' => $currencyCode !== '' ? $currencyCode : null,
|
||||
'pool' => [
|
||||
'provider_code' => $pool->provider_code ?? BetProvider::DEFAULT_CODE,
|
||||
'normalized_number' => $pool->normalized_number,
|
||||
'total_cap_amount' => $cap,
|
||||
'locked_amount' => $locked,
|
||||
@@ -84,6 +90,7 @@ final class AdminRiskPoolShowController extends Controller
|
||||
{
|
||||
return [
|
||||
'id' => (int) $log->id,
|
||||
'provider_code' => $log->provider_code ?? BetProvider::DEFAULT_CODE,
|
||||
'action_type' => $log->action_type,
|
||||
'amount' => (int) $log->amount,
|
||||
'source_reason' => $log->source_reason,
|
||||
|
||||
Reference in New Issue
Block a user