CaiWuXiTong/tests/Feature/Business/WithdrawalBalanceAlertTest.php

220 lines
9.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Business;
use App\Business\WithdrawalBalanceAlertSynchronizer;
use App\Models\Auth\Permission;
use App\Models\Business\StoreReceivingAccount;
use App\Models\Business\Todo;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Modules\EcommerceFinance\Repositories\JushuitanShopBalanceRepository;
use Tests\Feature\FeatureTestCase;
class WithdrawalBalanceAlertTest extends FeatureTestCase
{
/** @var list<string> */
private array $temporaryFiles = [];
protected function setUp(): void
{
parent::setUp();
$this->user->attachPermission(
Permission::where('name', 'read-admin-panel')->firstOrFail(),
);
$this->withoutMiddleware(ThrottleRequests::class);
}
public function test_three_unchanged_balances_above_reserve_show_warning_and_create_one_todo(): void
{
Carbon::setTestNow('2026-10-24 10:00:00');
try {
$store = StoreReceivingAccount::query()->create([
'company_id' => $this->company->id,
'store_platform' => '京东',
'erp_store_name' => '京东-连续余额测试店',
'shop_name' => '京东-连续余额测试店',
'store_entity_name' => '连续余额测试主体',
'store_id' => 'JD-ALERT-001',
]);
foreach (['2026-10-21', '2026-10-22', '2026-10-23'] as $date) {
$this->insertBalanceSnapshot($date, '京东-连续余额测试店', 8000);
}
$sync = app(WithdrawalBalanceAlertSynchronizer::class);
$firstSync = $sync->syncForDate((int) $this->company->id, '2026-10-23');
$secondSync = $sync->syncForDate((int) $this->company->id, '2026-10-23');
$this->assertSame(1, $firstSync['created']);
$this->assertSame(0, $firstSync['updated']);
$this->assertSame(0, $secondSync['created']);
$this->assertSame(0, $secondSync['updated']);
$url = route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'fund-management',
'page' => 'withdrawal-management',
'balance_date' => '2026-10-23',
'platform' => '京东',
]);
$this->loginAs()->get($url)
->assertOk()
->assertSeeText('10月21日店铺余额')
->assertSeeText('10月22日店铺余额')
->assertSeeText('10月23日店铺余额')
->assertSeeText('已显示余额 1 条')
->assertSeeText('连续3天未变动')
->assertSeeText('8,000.00');
$title = '提现余额连续3天未变动|京东|京东-连续余额测试店';
$todo = Todo::withoutGlobalScopes()->where('company_id', $this->company->id)->where('title', $title)->first();
$this->assertNotNull($todo);
$this->assertSame('提现余额预警', $todo->category);
$this->assertSame('高', $todo->priority);
$this->assertSame('待处理', $todo->status);
$this->assertStringContainsString('2026-10-21 至 2026-10-23', (string) $todo->description);
$this->assertStringContainsString((string) $store->store_entity_name, (string) $todo->description);
$this->get($url)->assertOk();
$this->assertSame(
1,
Todo::withoutGlobalScopes()
->where('company_id', $this->company->id)
->where('category', '提现余额预警')
->count(),
);
$this->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'other',
'page' => 'todos',
]))
->assertOk()
->assertSeeText($title)
->assertSeeText('提现余额预警')
->assertSeeText('连续余额测试主体');
} finally {
Carbon::setTestNow();
}
}
public function test_alert_requires_three_matched_days_an_exact_unchanged_value_and_a_strict_excess(): void
{
Carbon::setTestNow('2026-10-24 10:00:00');
try {
foreach (['等于预留标准店', '余额发生变动店', '缺少一天店'] as $name) {
StoreReceivingAccount::query()->create([
'company_id' => $this->company->id,
'store_platform' => '京东',
'erp_store_name' => '京东-' . $name,
'shop_name' => '京东-' . $name,
'store_entity_name' => '预警边界测试主体',
]);
}
foreach (['2026-10-21' => 5000, '2026-10-22' => 5000, '2026-10-23' => 5000] as $date => $balance) {
$this->insertBalanceSnapshot($date, '京东-等于预留标准店', $balance);
}
foreach (['2026-10-21' => 8000, '2026-10-22' => 8000, '2026-10-23' => 7999.99] as $date => $balance) {
$this->insertBalanceSnapshot($date, '京东-余额发生变动店', $balance);
}
foreach (['2026-10-22' => 8000, '2026-10-23' => 8000] as $date => $balance) {
$this->insertBalanceSnapshot($date, '京东-缺少一天店', $balance);
}
$sync = app(WithdrawalBalanceAlertSynchronizer::class)->syncForDate(
(int) $this->company->id,
'2026-10-23',
);
$this->assertSame(0, $sync['created']);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'fund-management',
'page' => 'withdrawal-management',
'balance_date' => '2026-10-23',
'platform' => '京东',
]))->assertOk()->assertSeeText('未触发')->assertSeeText('数据不足');
$this->assertSame(0, DB::table('business_todos')->count());
} finally {
Carbon::setTestNow();
}
}
public function test_successful_balance_import_runs_alert_generation_automatically(): void
{
Carbon::setTestNow('2026-10-24 10:00:00');
try {
StoreReceivingAccount::query()->create([
'company_id' => $this->company->id,
'store_platform' => '京东',
'erp_store_name' => '京东-导入预警测试店',
'shop_name' => '京东-导入预警测试店',
'store_entity_name' => '导入预警测试主体',
]);
$this->insertBalanceSnapshot('2026-10-21', '京东-导入预警测试店', 7000);
$this->insertBalanceSnapshot('2026-10-22', '京东-导入预警测试店', 7000);
$path = sys_get_temp_dir() . '/jst-balance-alert-' . uniqid('', true) . '.json';
$this->temporaryFiles[] = $path;
file_put_contents($path, json_encode([
'fldHeads' => [
['title' => '店铺', 'fld' => '店铺'],
['title' => '平台实际期末余额', 'fld' => '平台实际期末余额'],
],
'dataList' => [
['店铺' => '京东-导入预警测试店', '平台实际期末余额' => 7000],
],
], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
$this->artisan('business:import-jushuitan-shop-balances', [
'path' => $path,
'--balance-date' => '2026-10-23',
'--scope' => 'jd-wallet',
])->assertExitCode(0);
$this->assertDatabaseHas('business_todos', [
'company_id' => $this->company->id,
'title' => '提现余额连续3天未变动|京东|京东-导入预警测试店',
'category' => '提现余额预警',
'status' => '待处理',
]);
} finally {
Carbon::setTestNow();
}
}
protected function tearDown(): void
{
foreach ($this->temporaryFiles as $path) {
if (is_file($path)) {
unlink($path);
}
}
parent::tearDown();
}
private function insertBalanceSnapshot(string $date, string $storeName, float $balance): void
{
DB::connection('business_mirror')->table(JushuitanShopBalanceRepository::TABLE)->insert([
'balance_date' => $date,
'source_scope' => 'jd-wallet',
'source_platform' => '京东',
'store_name' => $storeName,
'normalized_store_name' => JushuitanShopBalanceRepository::normalizeStoreName($storeName),
'platform_account_id' => 'fixture-' . $storeName,
'balance' => $balance,
'source_row_key' => hash('sha256', $date . '|' . $storeName),
'source_file_name' => 'fixture.xlsx',
'source_sha256' => hash('sha256', 'fixture-' . $date . '-' . $storeName),
'imported_at' => now(),
'created_at' => now(),
'updated_at' => now(),
]);
}
}