|
|
@@ -0,0 +1,343 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace Tests\Integration;
|
|
|
+
|
|
|
+use App\Console\Commands\MigrateFrozenRewards;
|
|
|
+use App\Models\Wallet;
|
|
|
+use App\Models\Withdraw;
|
|
|
+use App\Services\BalanceLogService;
|
|
|
+use App\Services\ManualAuditService;
|
|
|
+use App\Services\WageringService;
|
|
|
+use App\Services\WalletFreezeService;
|
|
|
+use App\Services\WithdrawFundsService;
|
|
|
+use Illuminate\Config\Repository;
|
|
|
+use Illuminate\Database\Capsule\Manager;
|
|
|
+use Illuminate\Database\Schema\Blueprint;
|
|
|
+use Illuminate\Foundation\Application;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+use Illuminate\Support\Facades\Facade;
|
|
|
+use PHPUnit\Framework\TestCase;
|
|
|
+use Symfony\Component\Console\Input\ArrayInput;
|
|
|
+use Symfony\Component\Console\Output\BufferedOutput;
|
|
|
+
|
|
|
+/** 统一提现打码量、人工冻结/解冻与提现冻结,直接跑真实服务和上线迁移(SQLite)。 */
|
|
|
+class WageringTest extends TestCase
|
|
|
+{
|
|
|
+ private Application $app;
|
|
|
+
|
|
|
+ protected function setUp(): void
|
|
|
+ {
|
|
|
+ Facade::clearResolvedInstances();
|
|
|
+ $this->app = new Application(dirname(__DIR__, 2));
|
|
|
+ $this->app->instance('config', new Repository(['app' => ['timezone' => 'Asia/Shanghai'], 'third_game' => ['currency' => 'CNY']]));
|
|
|
+ Facade::setFacadeApplication($this->app);
|
|
|
+ $db = new Manager($this->app);
|
|
|
+ $db->addConnection(['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'bot_']);
|
|
|
+ $db->setAsGlobal();
|
|
|
+ $db->bootEloquent();
|
|
|
+ $this->app->instance('db', $db->getDatabaseManager());
|
|
|
+ $this->app->bind('db.schema', fn () => $db->schema());
|
|
|
+ $schema = $db->schema();
|
|
|
+ $schema->create('users', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id')->unique(); $t->string('account')->default(''); $t->string('username')->default('');
|
|
|
+ $t->string('first_name')->default(''); $t->integer('from')->default(1); $t->integer('level')->default(0);
|
|
|
+ $t->integer('recharge_channel_group_id')->default(1); $t->string('agent_user_code')->nullable(); $t->string('user_code')->nullable();
|
|
|
+ $t->string('language')->default('zh'); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('wallets', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->unsignedBigInteger('user_id')->nullable(); $t->string('member_id')->unique();
|
|
|
+ $t->decimal('available_balance', 30, 10)->default(0); $t->decimal('frozen_balance', 30, 10)->default(0);
|
|
|
+ $t->decimal('flow_balance', 10, 2)->default(0); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('balance_logs', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->integer('type')->default(1); $t->string('change_type'); $t->decimal('amount', 30, 10);
|
|
|
+ $t->decimal('before_balance', 30, 10)->nullable(); $t->decimal('after_balance', 30, 10)->nullable();
|
|
|
+ $t->integer('related_id')->nullable(); $t->integer('room_id')->nullable(); $t->integer('frozen_status')->nullable();
|
|
|
+ $t->text('remark')->nullable(); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('config', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('field'); $t->string('val'); $t->string('remark')->default(''); $t->integer('group_id')->default(1); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('level', function (Blueprint $t) { $t->id(); $t->integer('level'); $t->decimal('recharge', 20, 2); $t->timestamps(); });
|
|
|
+ $schema->create('recharge_channel_group', function (Blueprint $t) { $t->id(); $t->text('activity_type')->nullable(); $t->softDeletes(); $t->timestamps(); });
|
|
|
+ $schema->create('backflow', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->string('date');
|
|
|
+ foreach (['recharge_amount', 'withdrawal_amount', 'backflow_ratio', 'amount'] as $field) $t->decimal($field, 20, 2)->default(0);
|
|
|
+ $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('withdraws', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->decimal('amount', 30, 10); $t->decimal('service_charge', 30, 10)->default(0);
|
|
|
+ $t->decimal('to_account', 30, 10)->default(0); $t->string('address')->default(''); $t->decimal('exchange_rate', 20, 4)->default(1);
|
|
|
+ $t->integer('status')->default(0); $t->decimal('after_balance', 30, 10)->nullable(); $t->string('remark')->nullable(); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('payment_orders', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->integer('type'); $t->integer('status'); $t->decimal('amount', 30, 10); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('share_bet_facts', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('source', 32); $t->string('source_id', 64); $t->unsignedBigInteger('user_id'); $t->string('member_id', 64);
|
|
|
+ $t->string('category', 32)->default('lottery'); $t->dateTime('bet_at'); $t->date('bet_date'); $t->dateTime('settled_at')->nullable();
|
|
|
+ foreach (['bet_amount', 'net_profit', 'effective_amount'] as $c) $t->decimal($c, 24, 10)->default(0);
|
|
|
+ $t->boolean('settled')->default(true); $t->boolean('voided')->default(false); $t->string('currency', 8)->default('CNY');
|
|
|
+ $t->string('source_version', 64)->default('1'); $t->timestamps();
|
|
|
+ });
|
|
|
+ $schema->create('admin', function (Blueprint $t) { $t->id(); $t->string('username'); $t->timestamps(); });
|
|
|
+ DB::table('config')->insert([
|
|
|
+ ['field' => 'huishui_percentage', 'val' => '0'], ['field' => 'huishui_restriction', 'val' => '999999'], ['field' => 'recharge_rate', 'val' => '0'],
|
|
|
+ ]);
|
|
|
+ DB::table('level')->insert(['level' => 0, 'recharge' => '0']);
|
|
|
+ DB::table('admin')->insert(['id' => 9, 'username' => 'auditor']);
|
|
|
+ DB::table('recharge_channel_group')->insert(['id' => 1, 'activity_type' => '']);
|
|
|
+ DB::table('users')->insert(['id' => 1, 'member_id' => 'm1', 'account' => 'acc1', 'created_at' => '2026-01-01 00:00:00']);
|
|
|
+ DB::table('wallets')->insert(['user_id' => 1, 'member_id' => 'm1', 'available_balance' => '100', 'created_at' => '2026-01-01 00:00:00']);
|
|
|
+ WageringService::flushSchemaCache();
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_11_04_140000_create_wagering_and_wallet_freezes.php')->up();
|
|
|
+ WageringService::flushSchemaCache();
|
|
|
+ DB::table('config')->where('field', WageringService::CONFIG_FIELD)->update(['val' => '2']);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function tearDown(): void
|
|
|
+ {
|
|
|
+ WageringService::flushSchemaCache();
|
|
|
+ DB::disconnect();
|
|
|
+ Facade::clearResolvedInstances();
|
|
|
+ parent::tearDown();
|
|
|
+ }
|
|
|
+
|
|
|
+ private function wallet(): Wallet
|
|
|
+ {
|
|
|
+ return Wallet::where('member_id', 'm1')->first();
|
|
|
+ }
|
|
|
+
|
|
|
+ private function bet(string $stake, string $profit): void
|
|
|
+ {
|
|
|
+ static $id = 0;
|
|
|
+ $now = now('Asia/Shanghai')->format('Y-m-d H:i:s');
|
|
|
+ DB::table('share_bet_facts')->insert(['source' => 'lhc_order_item', 'source_id' => (string)++$id, 'user_id' => 1, 'member_id' => 'm1',
|
|
|
+ 'bet_at' => $now, 'bet_date' => substr($now, 0, 10), 'bet_amount' => $stake, 'net_profit' => $profit, 'created_at' => $now, 'updated_at' => $now]);
|
|
|
+ }
|
|
|
+
|
|
|
+ private function hold(string $amount): Withdraw
|
|
|
+ {
|
|
|
+ [$order] = WithdrawFundsService::hold('m1', $amount, '提现', '', WithdrawFundsService::WITHDRAWS,
|
|
|
+ fn ($before, $after) => Withdraw::create(['member_id' => 'm1', 'amount' => $amount, 'status' => 0, 'after_balance' => $after]));
|
|
|
+ return $order;
|
|
|
+ }
|
|
|
+
|
|
|
+ private function money($value): string
|
|
|
+ {
|
|
|
+ return bcadd((string)$value, '0', 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ private function assertBlocked(callable $work, string $message): void
|
|
|
+ {
|
|
|
+ try { $work(); $this->fail('Expected: ' . $message); }
|
|
|
+ catch (\Exception $e) { $this->assertStringContainsString($message, $e->getMessage()); }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_migration_starts_a_cycle_and_configures_the_platform_multiple(): void
|
|
|
+ {
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('2026-01-01 00:00:00', (string)$wallet->wager_cycle_from);
|
|
|
+ $this->assertSame('[]', (string)$wallet->wager_cycle_cursors);
|
|
|
+ $this->assertSame('2.0000000000', WageringService::multiple());
|
|
|
+ $this->assertSame(1, DB::table('config')->where('field', WageringService::CONFIG_FIELD)->count());
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_deposit_requirement_blocks_withdrawal_until_effective_bets_complete_it_then_resets(): void
|
|
|
+ {
|
|
|
+ BalanceLogService::addLog('m1', '100', '0', '100', '人工充值', null, '');
|
|
|
+ $this->assertSame('200.00', $this->money($this->wallet()->wager_required));
|
|
|
+ $this->assertSame('recharge', DB::table('wager_records')->value('source'));
|
|
|
+
|
|
|
+ $this->bet('150', '-150');
|
|
|
+ $this->assertBlocked(fn () => $this->hold('50'), '剩余打码量:50.00');
|
|
|
+ $this->bet('100', '1'); // 有效投注 = min(本金, |盈亏|) = 1
|
|
|
+ $this->assertBlocked(fn () => $this->hold('50'), '剩余打码量:49.00');
|
|
|
+ $this->bet('49', '49');
|
|
|
+ $this->assertSame(['wager_required' => '200.00', 'wager_completed' => '200.00', 'wager_remaining' => '0.00'],
|
|
|
+ WageringService::summary(tap($this->wallet(), fn ($w) => WageringService::refresh($w))));
|
|
|
+
|
|
|
+ $order = $this->hold('50');
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('50.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('50.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('50.00', $this->money($order->fresh()->frozen_amount));
|
|
|
+ $this->assertSame(['wager_required' => '0.00', 'wager_completed' => '0.00', 'wager_remaining' => '0.00'], WageringService::summary($wallet));
|
|
|
+ $this->assertSame(1, (int)$wallet->wager_cycle_id);
|
|
|
+ $this->assertSame('holding', DB::table('wallet_freeze_records')->where('type', 'withdraw_hold')->value('status'));
|
|
|
+ $this->assertSame('-50.00', $this->money(DB::table('balance_logs')->where('change_type', '提现')->value('amount')));
|
|
|
+ // 新周期只统计重置后的新注单
|
|
|
+ WageringService::refresh($wallet);
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->fresh()->wager_completed));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_requirements_from_several_sources_add_up_and_any_unfinished_one_blocks(): void
|
|
|
+ {
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ WageringService::addRequirement($wallet, '30', 'activity:即充即送', 1);
|
|
|
+ WageringService::addRequirement($wallet, '20', 'activity:promotion', 2);
|
|
|
+ $this->bet('45', '-45');
|
|
|
+ $this->assertBlocked(fn () => $this->hold('10'), '剩余打码量:5.00');
|
|
|
+ $this->bet('5', '-5');
|
|
|
+ $this->hold('10');
|
|
|
+ $this->assertSame('90.00', $this->money($this->wallet()->available_balance));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_requirement_increment_is_kept_when_the_caller_holds_a_stale_wallet(): void
|
|
|
+ {
|
|
|
+ $stale = $this->wallet();
|
|
|
+ WageringService::addRequirementFor('m1', '50', 'recharge', 1);
|
|
|
+ WageringService::addRequirement($stale, '20', 'activity:promotion', 2);
|
|
|
+ $this->assertSame('70.00', $this->money($this->wallet()->wager_required));
|
|
|
+ $this->assertSame('50.00', $this->money(DB::table('wager_records')->where('source_id', '2')->value('before_required')));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_reward_without_requirement_is_withdrawable_and_requirement_never_goes_negative(): void
|
|
|
+ {
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertNull(WageringService::addRequirement($wallet, '0', 'activity:即充即送', 1));
|
|
|
+ WageringService::addRequirement($wallet, '-5', 'freeze', 1);
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->fresh()->wager_required));
|
|
|
+ $this->hold('10');
|
|
|
+ $this->assertSame('90.00', $this->money($this->wallet()->available_balance));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_reject_releases_and_approve_settles_the_frozen_withdrawal_exactly_once(): void
|
|
|
+ {
|
|
|
+ $order = $this->hold('40');
|
|
|
+ $this->assertNotNull(WithdrawFundsService::release(WithdrawFundsService::WITHDRAWS, $order, '999', '提现', ''));
|
|
|
+ $this->assertNull(WithdrawFundsService::release(WithdrawFundsService::WITHDRAWS, $order, '999', '提现', ''));
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('100.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('released', DB::table('wallet_freeze_records')->value('status'));
|
|
|
+ $this->assertSame('40.00', $this->money(DB::table('balance_logs')->where('change_type', '提现')->where('amount', '>', 0)->value('amount')));
|
|
|
+
|
|
|
+ $order = $this->hold('30');
|
|
|
+ WithdrawFundsService::settle(WithdrawFundsService::WITHDRAWS, $order);
|
|
|
+ WithdrawFundsService::settle(WithdrawFundsService::WITHDRAWS, $order);
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('70.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('settled', DB::table('wallet_freeze_records')->orderByDesc('id')->value('status'));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_orders_created_before_launch_keep_the_old_refund_behaviour(): void
|
|
|
+ {
|
|
|
+ $legacy = Withdraw::create(['member_id' => 'm1', 'amount' => '25', 'status' => 0]);
|
|
|
+ WithdrawFundsService::settle(WithdrawFundsService::WITHDRAWS, $legacy);
|
|
|
+ $this->assertSame('100.00', $this->money($this->wallet()->available_balance));
|
|
|
+ WithdrawFundsService::release(WithdrawFundsService::WITHDRAWS, $legacy, '25', '提现', '');
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('125.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->frozen_balance));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_manual_freeze_and_unfreeze_move_balance_and_adjust_wagering(): void
|
|
|
+ {
|
|
|
+ WageringService::addRequirement($this->wallet(), '100', 'recharge', 1);
|
|
|
+ $frozen = WalletFreezeService::freeze('11111111-1111-4111-8111-111111111111', 9, 'm1', '30', '40', '风控冻结');
|
|
|
+ $this->assertSame('人工冻结', $frozen['type_text']);
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('70.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('30.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('60.00', $this->money($wallet->wager_required));
|
|
|
+ $this->assertSame('-30.00', $this->money(DB::table('balance_logs')->where('change_type', '人工冻结')->value('amount')));
|
|
|
+
|
|
|
+ // 提现冻结的资金不能被人工解冻
|
|
|
+ $this->bet('60', '-60');
|
|
|
+ $this->hold('10');
|
|
|
+ $this->assertSame('40.00', $this->money($this->wallet()->frozen_balance));
|
|
|
+ $this->assertBlocked(fn () => WalletFreezeService::unfreeze('22222222-2222-4222-8222-222222222222', 9, 'm1', '35', '0', 'x'), '最多可解冻:30.00');
|
|
|
+
|
|
|
+ WalletFreezeService::unfreeze('33333333-3333-4333-8333-333333333333', 9, 'm1', '20', '15', '核实解冻');
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('80.00', $this->money($wallet->available_balance));
|
|
|
+ $this->assertSame('20.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('15.00', $this->money($wallet->wager_required)); // 提现已把周期重置为0,解冻再加15
|
|
|
+ $this->assertSame('10.0000000000', WalletFreezeService::manualFrozen('m1'));
|
|
|
+
|
|
|
+ // 同一 request_id 重放返回原记录,不同内容拒绝
|
|
|
+ $replay = WalletFreezeService::unfreeze('33333333-3333-4333-8333-333333333333', 9, 'm1', '20', '15', '核实解冻');
|
|
|
+ $this->assertSame(3, DB::table('wallet_freeze_records')->whereIn('type', ['manual_freeze', 'manual_unfreeze', 'withdraw_hold'])->count());
|
|
|
+ $this->assertSame('20.00', $replay['amount']);
|
|
|
+ $this->assertBlocked(fn () => WalletFreezeService::unfreeze('33333333-3333-4333-8333-333333333333', 9, 'm1', '21', '15', 'x'), 'request_id');
|
|
|
+
|
|
|
+ $list = WalletFreezeService::list(['member_id' => 'm1']);
|
|
|
+ $this->assertSame(3, $list['total']);
|
|
|
+ $this->assertSame('acc1', $list['data'][0]['account']);
|
|
|
+ $this->assertSame('auditor', $list['data'][0]['admin_name']);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_manual_balance_adjustment_wagering_rules(): void
|
|
|
+ {
|
|
|
+ $this->assertSame([WageringService::platformRequirement('10'), false], ManualAuditService::wagerDelta(false, '10', '人工充值', null, '999'));
|
|
|
+ $this->assertSame('20.0000000000', WageringService::platformRequirement('10'));
|
|
|
+ $this->assertSame(['30.0000000000', true], ManualAuditService::wagerDelta(false, '10', '注册赠送', null, '30'));
|
|
|
+ $this->assertSame(['0.0000000000', true], ManualAuditService::wagerDelta(false, '10', '优惠活动', null, null));
|
|
|
+ $this->assertSame(['-20.0000000000', true], ManualAuditService::wagerDelta(true, '10', '人工扣款', '人工充值', '999'));
|
|
|
+ $this->assertSame(['-5.0000000000', true], ManualAuditService::wagerDelta(true, '10', '人工扣款', '优惠活动', '5'));
|
|
|
+ $this->assertSame(['0', false], ManualAuditService::wagerDelta(true, '10', '人工扣款', null, null));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_refresh_never_overwrites_a_cycle_that_was_reset_meanwhile(): void
|
|
|
+ {
|
|
|
+ $stale = $this->wallet();
|
|
|
+ $this->bet('80', '-80');
|
|
|
+ Wallet::where('id', $stale->id)->update(['wager_cycle_id' => 5, 'wager_completed' => 0]);
|
|
|
+ WageringService::refresh($stale);
|
|
|
+ $this->assertSame('0.00', $this->money($this->wallet()->wager_completed));
|
|
|
+ WageringService::refresh($this->wallet());
|
|
|
+ $this->assertSame('80.00', $this->money($this->wallet()->wager_completed));
|
|
|
+ }
|
|
|
+
|
|
|
+ public function test_one_time_migration_moves_frozen_rewards_to_available_and_carries_their_wagering(): void
|
|
|
+ {
|
|
|
+ DB::table('wallets')->where('member_id', 'm1')->update(['frozen_balance' => '25', 'flow_balance' => '4']);
|
|
|
+ DB::table('balance_logs')->insert([
|
|
|
+ ['member_id' => 'm1', 'type' => 2, 'change_type' => '即充即送', 'amount' => '10', 'related_id' => 7, 'frozen_status' => 1],
|
|
|
+ ['member_id' => 'm1', 'type' => 2, 'change_type' => '老用户回归', 'amount' => '10', 'related_id' => 7, 'frozen_status' => 1],
|
|
|
+ ['member_id' => 'm1', 'type' => 2, 'change_type' => '老用户回归', 'amount' => '5', 'related_id' => 8, 'frozen_status' => 1],
|
|
|
+ ]);
|
|
|
+ DB::connection()->getSchemaBuilder()->create('wallet_bonus', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->integer('activity_id'); $t->integer('related_id')->nullable();
|
|
|
+ $t->decimal('amount', 20, 2); $t->decimal('need_flow', 20, 2); $t->decimal('remaind_flow', 20, 2); $t->integer('status'); $t->timestamps();
|
|
|
+ });
|
|
|
+ // 同一笔充值的两条同额奖励各自对应一条 wallet_bonus
|
|
|
+ DB::table('wallet_bonus')->insert([
|
|
|
+ ['member_id' => 'm1', 'activity_id' => 1, 'related_id' => 7, 'amount' => '10', 'need_flow' => '30', 'remaind_flow' => '30', 'status' => 1],
|
|
|
+ ['member_id' => 'm1', 'activity_id' => 2, 'related_id' => 7, 'amount' => '10', 'need_flow' => '10', 'remaind_flow' => '10', 'status' => 1],
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $run = function (array $options) {
|
|
|
+ $command = new MigrateFrozenRewards();
|
|
|
+ $command->setLaravel($this->app);
|
|
|
+ $output = new BufferedOutput();
|
|
|
+ $command->run(new ArrayInput($options), $output);
|
|
|
+ return $output->fetch();
|
|
|
+ };
|
|
|
+ $run(['--dry-run' => true]);
|
|
|
+ $this->assertSame('25.00', $this->money($this->wallet()->frozen_balance));
|
|
|
+ $this->assertSame(0, DB::table('wager_records')->count());
|
|
|
+
|
|
|
+ // 进行中的申请活动:一条是上线前的(迁移剩余打码量),一条已按新流程记过打码量(跳过)
|
|
|
+ DB::connection()->getSchemaBuilder()->create('activity_user', function (Blueprint $t) {
|
|
|
+ $t->id(); $t->string('member_id'); $t->integer('status'); $t->decimal('betting_amount', 20, 2); $t->decimal('effective_betting_amount', 20, 2);
|
|
|
+ });
|
|
|
+ DB::table('activity_user')->insert([
|
|
|
+ ['id' => 1, 'member_id' => 'm1', 'status' => \App\Models\ActivityUser::STATUS_IN_PROGRESS, 'betting_amount' => '20', 'effective_betting_amount' => '5'],
|
|
|
+ ['id' => 2, 'member_id' => 'm1', 'status' => \App\Models\ActivityUser::STATUS_IN_PROGRESS, 'betting_amount' => '100', 'effective_betting_amount' => '0'],
|
|
|
+ ]);
|
|
|
+ WageringService::addRequirement($this->wallet(), '100', 'activity:activity_user', 2, '新流程发奖');
|
|
|
+
|
|
|
+ $run([]);
|
|
|
+ $run([]); // 重复执行不重复处理
|
|
|
+ $wallet = $this->wallet();
|
|
|
+ $this->assertSame('0.00', $this->money($wallet->frozen_balance));
|
|
|
+ $this->assertSame('125.00', $this->money($wallet->available_balance));
|
|
|
+ // 新流程已记 100;两条同额奖励分别取 30 和 10,无记录的按1倍5,减去旧流水余额4;上线前的申请活动剩余 15
|
|
|
+ $this->assertSame('156.00', $this->money($wallet->wager_required));
|
|
|
+ $this->assertSame(0, DB::table('balance_logs')->where('type', 2)->where('frozen_status', 1)->count());
|
|
|
+ $this->assertSame(3, DB::table('balance_logs')->where('change_type', '流水解冻')->where('type', 1)->count());
|
|
|
+ }
|
|
|
+}
|