Add the period balance reconciliation page, permissions, financial closing balances, Jushuitan snapshots for Taobao Alipay, Pinduoduo and Douyin, and explicit unavailable states.
306 lines
12 KiB
PHP
306 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Business;
|
|
|
|
use App\Models\Auth\Permission;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Services\PeriodBalanceReconciliationService;
|
|
use Modules\EcommerceFinance\Services\StoreReceivingBalanceOverviewService;
|
|
use Tests\Feature\FeatureTestCase;
|
|
|
|
class StoreReceivingBalanceOverviewEndpointTest extends FeatureTestCase
|
|
{
|
|
public function test_overview_endpoint_returns_the_selected_month_payload(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-01', 'end' => '2026-10-31'],
|
|
'summary' => [
|
|
'opening_balance' => 100.0,
|
|
'income' => 30.0,
|
|
'expense' => 10.0,
|
|
'balance' => 120.0,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'complete' => true,
|
|
],
|
|
'platforms' => [],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('overview')->once()->with('2026-10')->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview', ['month' => '2026-10']))
|
|
->assertOk()
|
|
->assertJsonPath('month', '2026-10')
|
|
->assertJsonPath('summary.balance', 120)
|
|
->assertJsonPath('summary.complete', true);
|
|
}
|
|
|
|
public function test_overview_endpoint_accepts_an_explicit_date_range(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-05', 'end' => '2026-10-20'],
|
|
'summary' => [
|
|
'opening_balance' => 100.0,
|
|
'income' => 30.0,
|
|
'expense' => 10.0,
|
|
'balance' => 120.0,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'complete' => true,
|
|
],
|
|
'platforms' => [],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('overview')
|
|
->once()
|
|
->with('2026-10-05', '2026-10-20')
|
|
->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview', [
|
|
'start' => '2026-10-05',
|
|
'end' => '2026-10-20',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('period.start', '2026-10-05')
|
|
->assertJsonPath('period.end', '2026-10-20')
|
|
->assertJsonPath('summary.complete', true);
|
|
}
|
|
|
|
public function test_overview_page_uses_the_vue_mount_point(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$this->loginAs()
|
|
->get(route('business.pages.show', [
|
|
'section' => 'billing-transactions',
|
|
'page' => 'store-receiving-bills',
|
|
'tab' => 'balance-overview',
|
|
]))
|
|
->assertOk()
|
|
->assertSee('class="biz-card mt-6 business-blank-page"', false)
|
|
->assertSee('public/js/business/pages.min.js', false);
|
|
}
|
|
|
|
public function test_reconciliation_page_uses_the_same_vue_entry_point(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$this->loginAs()
|
|
->get(route('business.pages.show', [
|
|
'section' => 'billing-transactions',
|
|
'page' => 'period-balance-reconciliation',
|
|
]))
|
|
->assertOk()
|
|
->assertSee('class="biz-card mt-6 business-blank-page"', false)
|
|
->assertSee('public/js/business/pages.min.js', false);
|
|
}
|
|
|
|
public function test_reconciliation_endpoint_accepts_an_explicit_date_range(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-05', 'end' => '2026-10-20'],
|
|
'tolerance_yuan' => 200,
|
|
'financial' => ['summary' => ['balance' => 120.0], 'platforms' => []],
|
|
'dual_source' => ['status' => 'incomplete'],
|
|
'sources' => [],
|
|
'platforms' => [],
|
|
'stores' => [],
|
|
'summary' => ['connected_store_count' => 0],
|
|
'trend' => ['points' => [], 'by_platform' => [], 'by_store' => []],
|
|
];
|
|
$service = Mockery::mock(PeriodBalanceReconciliationService::class);
|
|
$service->shouldReceive('build')
|
|
->once()
|
|
->with('2026-10-05', '2026-10-20')
|
|
->andReturn($payload);
|
|
$this->app->instance(PeriodBalanceReconciliationService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview.reconciliation', [
|
|
'start' => '2026-10-05',
|
|
'end' => '2026-10-20',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('period.start', '2026-10-05')
|
|
->assertJsonPath('period.end', '2026-10-20')
|
|
->assertJsonPath('tolerance_yuan', 200);
|
|
}
|
|
|
|
public function test_income_detail_endpoint_returns_platform_store_and_bill_item_rows(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-01', 'end' => '2026-10-31'],
|
|
'summary' => [
|
|
'income' => 120.0,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'complete' => true,
|
|
],
|
|
'details' => [[
|
|
'platform_slug' => 'taobao-alipay',
|
|
'platform' => '淘系支付宝账户',
|
|
'store_name' => '测试店铺',
|
|
'bill_item' => '货款收入',
|
|
'amount' => 120.0,
|
|
]],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('incomeDetail')->once()->with('2026-10')->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview.income-detail', [
|
|
'month' => '2026-10',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('summary.income', 120)
|
|
->assertJsonPath('details.0.platform_slug', 'taobao-alipay')
|
|
->assertJsonPath('details.0.bill_item', '货款收入');
|
|
}
|
|
|
|
public function test_expense_detail_endpoint_returns_platform_store_and_bill_item_rows(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-01', 'end' => '2026-10-31'],
|
|
'summary' => [
|
|
'expense' => 88.0,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'complete' => true,
|
|
],
|
|
'details' => [[
|
|
'platform_slug' => 'jd-wallet',
|
|
'platform' => '京东网银钱包账户',
|
|
'store_name' => '测试店铺',
|
|
'bill_item' => '平台扣费',
|
|
'amount' => 88.0,
|
|
]],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('expenseDetail')->once()->with('2026-10')->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview.expense-detail', [
|
|
'month' => '2026-10',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('summary.expense', 88)
|
|
->assertJsonPath('details.0.platform_slug', 'jd-wallet')
|
|
->assertJsonPath('details.0.bill_item', '平台扣费');
|
|
}
|
|
|
|
public function test_balance_detail_endpoint_returns_platform_closing_balances(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-01', 'end' => '2026-10-31'],
|
|
'summary' => [
|
|
'balance' => 1049.07,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'complete' => true,
|
|
],
|
|
'details' => [[
|
|
'platform_slug' => 'taobao-alipay',
|
|
'platform' => '淘系支付宝账户',
|
|
'store_name' => '',
|
|
'bill_item' => '',
|
|
'amount' => 218.88,
|
|
]],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('balanceDetail')->once()->with('2026-10')->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview.balance-detail', [
|
|
'month' => '2026-10',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('summary.balance', 1049.07)
|
|
->assertJsonPath('details.0.platform_slug', 'taobao-alipay')
|
|
->assertJsonPath('details.0.amount', 218.88);
|
|
}
|
|
|
|
public function test_balance_store_detail_endpoint_returns_store_closing_balances(): void
|
|
{
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
|
|
$payload = [
|
|
'month' => '2026-10',
|
|
'period' => ['start' => '2026-10-01', 'end' => '2026-10-31'],
|
|
'summary' => [
|
|
'balance' => 1049.07,
|
|
'platform_count' => 8,
|
|
'available_platform_count' => 8,
|
|
'store_count' => 1,
|
|
'ready_store_count' => 1,
|
|
'complete' => true,
|
|
],
|
|
'details' => [[
|
|
'platform_slug' => 'taobao-alipay',
|
|
'platform' => '淘系支付宝账户',
|
|
'store_name' => '测试店铺',
|
|
'bill_item' => '',
|
|
'opening_balance' => 100.0,
|
|
'income' => 130.0,
|
|
'expense' => 10.0,
|
|
'amount' => 220.0,
|
|
'available' => true,
|
|
]],
|
|
];
|
|
$service = Mockery::mock(StoreReceivingBalanceOverviewService::class);
|
|
$service->shouldReceive('balanceStoreDetail')->once()->with('2026-10')->andReturn($payload);
|
|
$this->app->instance(StoreReceivingBalanceOverviewService::class, $service);
|
|
|
|
$this->loginAs()
|
|
->getJson(route('ecommerce-finance.account-bills.overview.balance-store-detail', [
|
|
'month' => '2026-10',
|
|
]))
|
|
->assertOk()
|
|
->assertJsonPath('summary.complete', true)
|
|
->assertJsonPath('details.0.store_name', '测试店铺')
|
|
->assertJsonPath('details.0.amount', 220);
|
|
}
|
|
}
|