feat: 添加结算功能,更新 TicketItem 模型以支持最新结算详情,增强 DrawTickService 以自动处理结算,更新 TicketWalletService 以支持派彩入账,扩展 API 路由以管理结算批次和奖池

This commit is contained in:
2026-05-11 15:34:34 +08:00
parent 6a55fa9592
commit 19003f5041
50 changed files with 3604 additions and 3 deletions

View File

@@ -0,0 +1,57 @@
<?php
namespace App\Services\Settlement\Matchers;
use App\Models\TicketCombination;
use App\Models\TicketItem;
use App\Services\Settlement\Contracts\SettlementPlayMatcher;
use App\Services\Settlement\OddsSnapshotReader;
use App\Services\Settlement\PublishedDrawResultBoard;
use Illuminate\Support\Collection;
/** pos_3a / pos_3b / pos_3c后三位命中对应档。头奖命中时 `matched_prize_tier` 为 firstJackpot 口径)。 */
final class Pos3TierSettlementMatcher implements SettlementPlayMatcher
{
/** @var array<string, string> */
private const PLAY_TO_TIER = [
'pos_3a' => 'first',
'pos_3b' => 'second',
'pos_3c' => 'third',
];
public function __construct(
private readonly OddsSnapshotReader $odds,
) {}
public function match(TicketItem $item, PublishedDrawResultBoard $board, Collection $combinations): array
{
$tier = self::PLAY_TO_TIER[$item->play_code] ?? 'first';
$suffix = $board->suffix3ForTier($tier, 0);
if ($suffix === '') {
return ['win_amount' => 0, 'matched_prize_tier' => null, 'match_detail' => ['reason' => 'no_suffix']];
}
$snapshot = is_array($item->odds_snapshot_json) ? $item->odds_snapshot_json : null;
$oddsVal = $this->odds->oddsValueForScope($snapshot, $tier);
$lines = [];
$total = 0;
foreach ($combinations as $c) {
/** @var TicketCombination $c */
$n = (string) $c->number_4d;
if (strlen($n) < 3 || substr($n, -3) !== $suffix) {
continue;
}
$bet = (int) $c->bet_amount;
$payout = (int) floor($bet * ($oddsVal / 10_000));
$total += $payout;
$lines[] = ['number_4d' => $n, 'suffix3' => $suffix, 'payout' => $payout];
}
return [
'win_amount' => $total,
'matched_prize_tier' => $total > 0 ? $tier : null,
'match_detail' => ['lines' => $lines],
];
}
}