Files
moonwell-web/tests/Feature/BalancePaymentsFeatureTest.php
T

122 lines
4.7 KiB
PHP

<?php
namespace Tests\Feature;
use App\Services\BalanceService;
use App\Services\RobokassaService;
use InvalidArgumentException;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class BalancePaymentsFeatureTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
config([
'database.default' => 'azerothcore_auth',
'database.connections.azerothcore_auth' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
'foreign_key_constraints' => true,
],
'services.robokassa.mode' => 'test',
'services.robokassa.environments.test' => [
'login' => 'moonwell-test',
'password1' => 'password-one',
'password2' => 'password-two',
'hash_algorithm' => 'md5',
],
'services.robokassa.environments.production' => [
'login' => 'moonwell-production',
'password1' => 'production-one',
'password2' => 'production-two',
'hash_algorithm' => 'sha256',
],
'services.robokassa.tears_per_ruble' => 10,
]);
DB::purge('azerothcore_auth');
$migration = require database_path('migrations/2026_07_19_000001_create_moonwell_balance_tables.php');
$migration->up();
}
public function test_valid_callback_credits_balance_only_once(): void
{
$robokassa = app(RobokassaService::class);
$invoice = $robokassa->createInvoice(7, '100.00');
$parameters = $robokassa->paymentParameters($invoice, 'player@example.com');
$callback = [
'OutSum' => '100.00',
'InvId' => (string) $invoice->id,
'Shp_account' => '7',
'SignatureValue' => md5('100.00:'.$invoice->id.':password-two:Shp_account=7'),
];
$robokassa->processResult($callback);
$robokassa->processResult($callback);
$this->assertSame('1', $parameters['IsTest']);
$this->assertSame('1000.00', app(BalanceService::class)->balance(7));
$this->assertDatabaseCount('balance_transactions', 1, 'azerothcore_auth');
}
public function test_game_spending_is_atomic_and_idempotent(): void
{
DB::connection('azerothcore_auth')->table('account_balances')->insert([
'account_id' => 7,
'balance' => '100.00',
'created_at' => now(),
'updated_at' => now(),
]);
$balances = app(BalanceService::class);
$first = $balances->spend(7, '25.50', 'game:purchase-42', 'Игровой предмет');
$second = $balances->spend(7, '25.50', 'game:purchase-42', 'Игровой предмет');
$this->assertSame($first->id, $second->id);
$this->assertSame('74.50', $balances->balance(7));
$this->assertDatabaseCount('balance_transactions', 1, 'azerothcore_auth');
}
public function test_production_mode_uses_production_credentials_and_disables_test_flag(): void
{
config(['services.robokassa.mode' => 'production']);
$robokassa = app(RobokassaService::class);
$invoice = $robokassa->createInvoice(7, '50.00');
$parameters = $robokassa->paymentParameters($invoice);
$this->assertSame('production', $invoice->mode);
$this->assertSame('moonwell-production', $parameters['MerchantLogin']);
$this->assertSame('0', $parameters['IsTest']);
$this->assertSame(
hash('sha256', 'moonwell-production:50.00:'.$invoice->id.':production-one:Shp_account=7'),
$parameters['SignatureValue'],
);
}
public function test_admin_can_credit_and_debit_with_audit_metadata(): void
{
$balances = app(BalanceService::class);
$credit = $balances->adjustByAdmin(7, '50.00', 'credit', 1, 'ADMIN', 'Компенсация');
$debit = $balances->adjustByAdmin(7, '12.50', 'debit', 1, 'ADMIN', 'Исправление');
$this->assertSame('37.50', $balances->balance(7));
$this->assertSame('admin_credit', $credit->type);
$this->assertSame('admin_debit', $debit->type);
$this->assertSame('ADMIN', $debit->metadata['admin_username']);
$this->assertSame('Исправление', $debit->metadata['reason']);
}
public function test_admin_cannot_debit_more_than_available_balance(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Недостаточно средств');
app(BalanceService::class)->adjustByAdmin(7, '1.00', 'debit', 1, 'ADMIN', 'Проверка');
}
}