223 lines
9.7 KiB
PHP
223 lines
9.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Database\Schema\Blueprint;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Modules\EcommerceFinance\Repositories\JdPromotionAccountBalanceRepository;
|
|
use RuntimeException;
|
|
use Tests\TestCase;
|
|
|
|
class JdPromotionAccountBalanceRepositoryTest extends TestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
CarbonImmutable::setTestNow('2026-09-12 12:00:00');
|
|
config([
|
|
'database.connections.business_mirror' => [
|
|
'driver' => 'sqlite',
|
|
'database' => ':memory:',
|
|
'prefix' => '',
|
|
],
|
|
'upstream_mirrors.connection' => 'business_mirror',
|
|
'upstream_mirrors.datasets' => [
|
|
JdPromotionAccountBalanceRepository::DATASET_KEY => [
|
|
'source_key' => 'js_data_middle_platform',
|
|
'schema' => 'dbo',
|
|
'object' => 'jd_jzt_finance_records',
|
|
'target' => 'fixture_jd_jzt_finance_records',
|
|
'keys' => ['id'],
|
|
'watermark' => 'updated_at',
|
|
],
|
|
],
|
|
]);
|
|
DB::purge('business_mirror');
|
|
|
|
Schema::connection('business_mirror')->create('business_mirror_table_states', function (Blueprint $table): void {
|
|
$table->string('dataset_key')->primary();
|
|
$table->dateTime('initial_completed_at')->nullable();
|
|
});
|
|
Schema::connection('business_mirror')->create('fixture_jd_jzt_finance_records', function (Blueprint $table): void {
|
|
$table->integer('id');
|
|
$table->string('data_month')->nullable();
|
|
$table->string('shop_name')->nullable();
|
|
$table->string('in_out_type')->nullable();
|
|
$table->string('in_out_type_name')->nullable();
|
|
$table->decimal('amount', 18, 2)->nullable();
|
|
$table->decimal('balance_amount', 18, 2)->nullable();
|
|
$table->dateTime('settle_datetime')->nullable();
|
|
$table->date('show_date')->nullable();
|
|
$table->dateTime('updated_at')->nullable();
|
|
});
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
CarbonImmutable::setTestNow();
|
|
DB::purge('business_mirror');
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_it_calculates_completed_month_balances_from_jd_jzt_rows(): void
|
|
{
|
|
$this->markReady();
|
|
DB::connection('business_mirror')->table('fixture_jd_jzt_finance_records')->insert([
|
|
$this->row(1, '京东A店', '2026-05-31', '2026-05-31 23:59:00', 'IN', '入账', 1000, 1000),
|
|
$this->row(2, '京东A店', '2026-06-01', '2026-06-01 09:00:00', 'IN', '入账', 500, 1500),
|
|
$this->row(3, '京东A店', '2026-06-30', '2026-06-30 10:00:00', 'OUT', '出账', 100, 1400),
|
|
$this->row(4, '京东A店', '2026-06-30', '2026-06-30 20:00:00', 'OUT', '出账', 100, 1300),
|
|
$this->row(5, '京东B店', '2026-06-30', '2026-06-30 18:00:00', 'OUT', '出账', 25, 75),
|
|
$this->row(6, '京东A店', '2026-09-01', '2026-09-01 09:00:00', 'IN', '入账', 10, 1310),
|
|
]);
|
|
|
|
$repository = app(JdPromotionAccountBalanceRepository::class);
|
|
$result = $repository->paginateMonthlyBalances(null, '2026-06', 1, 25);
|
|
|
|
$this->assertTrue($repository->usesBusinessMirror());
|
|
$this->assertSame(['京东A店', '京东B店'], $repository->storeOptions());
|
|
$this->assertSame(2, $result['total']);
|
|
$this->assertSame([
|
|
'date' => '2026-06-30',
|
|
'store_name' => '京东A店',
|
|
'opening_balance' => 1000.0,
|
|
'income_total' => 500.0,
|
|
'expense_total' => 200.0,
|
|
'closing_balance' => 1300.0,
|
|
'system_closing_balance' => 1300.0,
|
|
'balance_difference' => 0.0,
|
|
'difference_reason' => '',
|
|
'verification_status' => '已核对',
|
|
'notes' => '',
|
|
], $result['rows'][0]);
|
|
$this->assertNull($result['rows'][1]['opening_balance']);
|
|
$this->assertNull($result['rows'][1]['closing_balance']);
|
|
$this->assertSame('缺少上月期末余额', $result['rows'][1]['difference_reason']);
|
|
$this->assertSame('待核对', $result['rows'][1]['verification_status']);
|
|
}
|
|
|
|
public function test_store_and_month_filters_share_the_same_monthly_result(): void
|
|
{
|
|
$this->markReady();
|
|
DB::connection('business_mirror')->table('fixture_jd_jzt_finance_records')->insert([
|
|
$this->row(1, '京东A店', '2026-05-31', '2026-05-31 23:59:00', 'IN', '入账', 100, 100),
|
|
$this->row(2, '京东A店', '2026-06-30', '2026-06-30 23:59:00', 'IN', '入账', 20, 120),
|
|
$this->row(3, '京东B店', '2026-06-30', '2026-06-30 23:59:00', 'IN', '入账', 30, 30),
|
|
]);
|
|
|
|
$result = app(JdPromotionAccountBalanceRepository::class)
|
|
->paginateMonthlyBalances('京东A店', '2026-06', 1, 25);
|
|
|
|
$this->assertSame(1, $result['total']);
|
|
$this->assertSame('京东A店', $result['rows'][0]['store_name']);
|
|
$this->assertSame(100.0, $result['rows'][0]['opening_balance']);
|
|
$this->assertSame(20.0, $result['rows'][0]['income_total']);
|
|
}
|
|
|
|
public function test_it_does_not_treat_non_month_end_balances_as_month_end_balances(): void
|
|
{
|
|
$this->markReady();
|
|
DB::connection('business_mirror')->table('fixture_jd_jzt_finance_records')->insert([
|
|
$this->row(1, '京东A店', '2026-05-30', '2026-05-30 23:59:00', 'IN', '入账', 100, 100),
|
|
$this->row(2, '京东A店', '2026-06-01', '2026-06-01 09:00:00', 'IN', '入账', 20, 120),
|
|
$this->row(3, '京东A店', '2026-06-29', '2026-06-29 23:59:00', 'OUT', '出账', 5, 115),
|
|
]);
|
|
|
|
$row = app(JdPromotionAccountBalanceRepository::class)
|
|
->paginateMonthlyBalances('京东A店', '2026-06', 1, 25)['rows'][0];
|
|
|
|
$this->assertNull($row['opening_balance']);
|
|
$this->assertNull($row['system_closing_balance']);
|
|
$this->assertNull($row['closing_balance']);
|
|
$this->assertNull($row['balance_difference']);
|
|
$this->assertSame('缺少期初余额和系统期末余额', $row['difference_reason']);
|
|
$this->assertSame('待核对', $row['verification_status']);
|
|
}
|
|
|
|
public function test_it_identifies_a_missing_current_month_end_balance(): void
|
|
{
|
|
$this->markReady();
|
|
DB::connection('business_mirror')->table('fixture_jd_jzt_finance_records')->insert([
|
|
$this->row(1, '京东A店', '2026-05-31', '2026-05-31 23:59:00', 'IN', '入账', 100, 100),
|
|
$this->row(2, '京东A店', '2026-06-01', '2026-06-01 09:00:00', 'IN', '入账', 20, 120),
|
|
$this->row(3, '京东A店', '2026-06-29', '2026-06-29 23:59:00', 'OUT', '出账', 5, 115),
|
|
]);
|
|
|
|
$row = app(JdPromotionAccountBalanceRepository::class)
|
|
->paginateMonthlyBalances('京东A店', '2026-06', 1, 25)['rows'][0];
|
|
|
|
$this->assertSame(100.0, $row['opening_balance']);
|
|
$this->assertSame(115.0, $row['closing_balance']);
|
|
$this->assertNull($row['system_closing_balance']);
|
|
$this->assertNull($row['balance_difference']);
|
|
$this->assertSame('缺少本月系统期末余额', $row['difference_reason']);
|
|
$this->assertSame('待核对', $row['verification_status']);
|
|
}
|
|
|
|
public function test_it_explains_a_non_zero_balance_difference(): void
|
|
{
|
|
$this->markReady();
|
|
DB::connection('business_mirror')->table('fixture_jd_jzt_finance_records')->insert([
|
|
$this->row(1, '京东A店', '2026-05-31', '2026-05-31 23:59:00', 'IN', '入账', 100, 100),
|
|
$this->row(2, '京东A店', '2026-06-30', '2026-06-30 23:59:00', 'IN', '入账', 20, 125),
|
|
]);
|
|
|
|
$row = app(JdPromotionAccountBalanceRepository::class)
|
|
->paginateMonthlyBalances('京东A店', '2026-06', 1, 25)['rows'][0];
|
|
|
|
$this->assertSame(120.0, $row['closing_balance']);
|
|
$this->assertSame(125.0, $row['system_closing_balance']);
|
|
$this->assertSame(5.0, $row['balance_difference']);
|
|
$this->assertSame('系统期末余额与计算期末余额相差 5.00 元', $row['difference_reason']);
|
|
$this->assertSame('待核对', $row['verification_status']);
|
|
}
|
|
|
|
public function test_it_rejects_an_incomplete_shared_mirror(): void
|
|
{
|
|
$repository = app(JdPromotionAccountBalanceRepository::class);
|
|
|
|
$this->assertFalse($repository->usesBusinessMirror());
|
|
$this->expectException(RuntimeException::class);
|
|
$this->expectExceptionMessage('京东账户余额共享业务镜像尚未完成同步。');
|
|
|
|
$repository->paginateMonthlyBalances(null, '2026-06', 1, 25);
|
|
}
|
|
|
|
private function markReady(): void
|
|
{
|
|
DB::connection('business_mirror')->table('business_mirror_table_states')->insert([
|
|
'dataset_key' => JdPromotionAccountBalanceRepository::DATASET_KEY,
|
|
'initial_completed_at' => '2026-09-12 10:00:00',
|
|
]);
|
|
}
|
|
|
|
/** @return array<string,mixed> */
|
|
private function row(
|
|
int $id,
|
|
string $shop,
|
|
string $date,
|
|
string $settledAt,
|
|
string $type,
|
|
string $typeName,
|
|
float $amount,
|
|
float $balance,
|
|
): array {
|
|
return [
|
|
'id' => $id,
|
|
'data_month' => substr($date, 0, 7),
|
|
'shop_name' => $shop,
|
|
'in_out_type' => $type,
|
|
'in_out_type_name' => $typeName,
|
|
'amount' => $amount,
|
|
'balance_amount' => $balance,
|
|
'settle_datetime' => $settledAt,
|
|
'show_date' => $date,
|
|
'updated_at' => $settledAt,
|
|
];
|
|
}
|
|
}
|