|
|
@@ -597,6 +597,98 @@ class ReportingTest extends TestCase
|
|
|
$this->assertSame(4, DB::table('reporting_orders')->count());
|
|
|
}
|
|
|
|
|
|
+ public static function thirdPartyReportCases(): array
|
|
|
+ {
|
|
|
+ $cases = [];
|
|
|
+ foreach (range(1, 7) as $type) foreach ([
|
|
|
+ 'win' => [1, '80', '100', '180', '0', '-80'],
|
|
|
+ 'loss' => [1, '-100', '100', '0', '0', '100'],
|
|
|
+ 'push' => [1, '0', '100', '100', '0', '0'],
|
|
|
+ 'pending' => [0, '0', '0', '0', '0', '0'],
|
|
|
+ 'void' => [2, '0', '0', '0', '100', '0'],
|
|
|
+ 'cancelled' => [3, '0', '0', '0', '100', '0'],
|
|
|
+ ] as $name => $values) $cases[$type . '-' . $name] = [$type, ...$values];
|
|
|
+ return $cases;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @dataProvider thirdPartyReportCases */
|
|
|
+ public function test_third_party_categories_use_provider_settlement_time_and_preserve_net_payout_math(int $type, int $status, string $net, string $stake, string $payout, string $refund, string $gross): void
|
|
|
+ {
|
|
|
+ DB::statement('CREATE TABLE bot_third_game_orders (id INTEGER PRIMARY KEY,order_key TEXT,member_id TEXT,user_id INTEGER,game_type INTEGER,bet_amount TEXT,settled_amount TEXT,status INTEGER,currency TEXT,bet_time TEXT,last_update_time TEXT,created_at TEXT,updated_at TEXT)');
|
|
|
+ DB::table('third_game_orders')->insert(['id' => 1, 'order_key' => str_repeat('b', 64), 'member_id' => '200', 'user_id' => 2, 'game_type' => $type,
|
|
|
+ 'bet_amount' => '100', 'settled_amount' => $net, 'status' => $status, 'currency' => 'CNY', 'bet_time' => '2026-10-25 23:00:00',
|
|
|
+ 'last_update_time' => '2026-10-26 10:00:00', 'created_at' => '2026-10-26 12:00:00', 'updated_at' => '2026-10-26 13:00:00']);
|
|
|
+ $this->sync->publish('third_game_orders', 1); $this->sync->publish('third_game_orders', 1);
|
|
|
+ $day = $this->reader->funds($this->today())['summary'];
|
|
|
+ $report = $this->reader->summary($this->today());
|
|
|
+ $category = collect($report['categories'])->keyBy('group_id')['third:' . $type];
|
|
|
+ foreach ([$day, $category, $this->reader->summary($this->today(['report_type' => 'sharing']))['summary']] as $row) {
|
|
|
+ $this->assertSame('0.0000000000', $row['bet_amount']);
|
|
|
+ $this->assertSame(bcadd($stake, '0', 10), $row['settled_bet_amount']);
|
|
|
+ $this->assertSame(bcadd($payout, '0', 10), $row['payout_amount']);
|
|
|
+ $this->assertSame(bcadd($refund, '0', 10), $row['refund_amount']);
|
|
|
+ $this->assertSame(bcadd($gross, '0', 10), $row['game_gross_profit']);
|
|
|
+ }
|
|
|
+ $previous = $this->reader->summary(['start_date' => '2026-10-25', 'end_date' => '2026-10-25'])['summary'];
|
|
|
+ $this->assertSame('100.0000000000', $previous['bet_amount']);
|
|
|
+ $this->assertSame('0.0000000000', $previous['payout_amount']);
|
|
|
+ $this->assertSame(1, DB::table('reporting_orders')->count());
|
|
|
+ $this->assertSame($status === 0 ? null : '2026-10-26 10:00:00', DB::table('reporting_orders')->value('settled_at'));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function sportsReportCases(): array
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ 'win' => [1, 1, 0, '180', '0', '100', '180', '0', '-80'],
|
|
|
+ 'loss' => [1, 1, 0, '0', '0', '100', '0', '0', '100'],
|
|
|
+ 'half-loss' => [1, 1, 1, '0', '50', '50', '0', '50', '50'],
|
|
|
+ 'push' => [1, 1, 1, '0', '100', '0', '0', '100', '0'],
|
|
|
+ 'awaiting-payout' => [1, 2, 0, '180', '0', '0', '0', '0', '0'],
|
|
|
+ 'void' => [2, 0, 2, '0', '100', '0', '0', '100', '0'],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @dataProvider sportsReportCases */
|
|
|
+ public function test_f1_sports_uses_official_settlement_or_refund_time(int $status, int $settlement, int $returnStatus, string $win, string $returned, string $stake, string $payout, string $refund, string $gross): void
|
|
|
+ {
|
|
|
+ DB::statement('CREATE TABLE bot_sport_order (id INTEGER PRIMARY KEY,user_id TEXT,amount TEXT,win_amount TEXT,return_amount TEXT,status INTEGER,pay_status INTEGER,settlement_status INTEGER,return_status INTEGER,create_time INTEGER,update_time INTEGER,settlement_time INTEGER,return_operation_time INTEGER)');
|
|
|
+ DB::table('sport_order')->insert(['id' => 1, 'user_id' => '200', 'amount' => '100', 'win_amount' => $win, 'return_amount' => $returned,
|
|
|
+ 'status' => $status, 'pay_status' => 1, 'settlement_status' => $settlement, 'return_status' => $returnStatus,
|
|
|
+ 'create_time' => Carbon::parse('2026-10-25 23:00:00', 'Asia/Shanghai')->timestamp,
|
|
|
+ 'update_time' => Carbon::parse('2026-10-26 13:00:00', 'Asia/Shanghai')->timestamp,
|
|
|
+ 'settlement_time' => $status === 2 ? null : Carbon::parse('2026-10-26 10:00:00', 'Asia/Shanghai')->timestamp,
|
|
|
+ 'return_operation_time' => $status === 2 ? Carbon::parse('2026-10-26 11:00:00', 'Asia/Shanghai')->timestamp : null]);
|
|
|
+ $this->sync->publish('sport_order', 1);
|
|
|
+ $category = collect($this->reader->summary($this->today())['categories'])->keyBy('group_id')['self:sport'];
|
|
|
+ foreach ([$category, $this->reader->funds($this->today())['summary']] as $row) {
|
|
|
+ $this->assertSame(bcadd($stake, '0', 10), $row['settled_bet_amount']);
|
|
|
+ $this->assertSame(bcadd($payout, '0', 10), $row['payout_amount']);
|
|
|
+ $this->assertSame(bcadd($refund, '0', 10), $row['refund_amount']);
|
|
|
+ $this->assertSame(bcadd($gross, '0', 10), $row['game_gross_profit']);
|
|
|
+ }
|
|
|
+ $this->assertSame($settlement === 2 ? null : ($status === 2 ? '2026-10-26 11:00:00' : '2026-10-26 10:00:00'), DB::table('reporting_orders')->value('settled_at'));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_legacy_sport_game_job_captures_losses_as_well_as_wins_for_reporting(): void
|
|
|
+ {
|
|
|
+ DB::statement('CREATE TABLE bot_sport_game_order (id INTEGER PRIMARY KEY,member_id TEXT,gameplay_id INTEGER,amount TEXT,odds TEXT,status INTEGER,win_amount TEXT,profit_and_loss TEXT,created_at TEXT,updated_at TEXT)');
|
|
|
+ DB::statement('CREATE TABLE bot_wallets (id INTEGER PRIMARY KEY,member_id TEXT,available_balance TEXT,frozen_balance TEXT,created_at TEXT,updated_at TEXT)');
|
|
|
+ DB::table('wallets')->insert(['id' => 1, 'member_id' => '200', 'available_balance' => '100', 'frozen_balance' => '0']);
|
|
|
+ DB::table('sport_game_order')->insert([
|
|
|
+ ['id' => 1, 'member_id' => '200', 'gameplay_id' => 1, 'amount' => '100', 'odds' => '1.8', 'status' => 0, 'created_at' => '2026-10-26 09:00:00'],
|
|
|
+ ['id' => 2, 'member_id' => '200', 'gameplay_id' => 2, 'amount' => '50', 'odds' => '1.8', 'status' => 0, 'created_at' => '2026-10-26 09:00:00'],
|
|
|
+ ]);
|
|
|
+ $this->context('sport_game_order', 1); $this->context('sport_game_order', 2);
|
|
|
+ (new \App\Jobs\SportGameOrderJob(1))->handle();
|
|
|
+ $this->sync->publish('sport_game_order', 1); $this->sync->publish('sport_game_order', 2);
|
|
|
+ $row = $this->reader->funds($this->today())['summary'];
|
|
|
+ $this->assertSame('150.0000000000', $row['settled_bet_amount']);
|
|
|
+ $this->assertSame('180.0000000000', $row['payout_amount']);
|
|
|
+ $this->assertSame('-30.0000000000', $row['game_gross_profit']);
|
|
|
+ $this->assertSame('280.00', bcadd((string) DB::table('wallets')->where('id', 1)->value('available_balance'), '0', 2));
|
|
|
+ $this->assertSame(0, DB::transactionLevel());
|
|
|
+ }
|
|
|
+
|
|
|
public function test_audit_failure_rolls_back_reconciliation_and_foreign_currency_is_not_summed(): void
|
|
|
{
|
|
|
$event = $this->deposit();
|