122 lines
4.7 KiB
PHP
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', 'Проверка');
|
|
}
|
|
}
|