CaiWuXiTong/tests/Feature/Business/ThirdPartyWarehouseQuotePageTest.php

227 lines
10 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\Http\Livewire\Business\ThirdPartyWarehouseQuotes as WarehouseQuoteComponent;
use App\Models\Auth\Permission;
use App\Models\Business\ThirdPartyWarehouseQuote;
use App\Models\Business\ThirdPartyWarehouseStorageSettlement;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Livewire\Livewire;
use Tests\Feature\FeatureTestCase;
class ThirdPartyWarehouseQuotePageTest extends FeatureTestCase
{
public function test_quote_management_contains_warehouse_quote_entry_and_formula_definitions(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->createQuote();
$this->loginAs()
->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'quote-management',
'quote_view' => 'warehouse',
]))
->assertOk()
->assertSeeText('快递报价')
->assertSeeText('仓储报价')
->assertSeeText('录入新报价')
->assertSeeText('南昌樵舍仓')
->assertSeeText('入库管理费(元/吨)')
->assertSeeText('出库费(元/单)')
->assertSeeText('每托折算件数(件/托)')
->assertSeeText('每托占地面积(㎡/托)')
->assertSeeText('仓储面积单价(元/㎡·月)')
->assertSeeText('Σ(普通商品资料重量kg ÷ 1000 ×(加工进仓+加工出仓+采购进仓+采购退货+其它退货+销售退货+盘点+调拨入))× 入库管理费单价')
->assertSeeText('Σ(销售出仓 + 其它出库 + 调拨出)× 出库费单价')
->assertSeeText('系统数据为唯一核算来源,不读取仓库提供、核对或差异列')
->assertSeeText($this->user->name)
->assertSee('data-quote-panel="warehouse"', false);
}
public function test_warehouse_quote_store_creates_a_new_effective_version(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
$existing = $this->createQuote();
Livewire::test(WarehouseQuoteComponent::class)
->set('warehouseName', '南昌樵舍仓')
->set('inboundRatePerTon', '22.5')
->set('outboundRatePerOrder', '0.9')
->set('piecesPerPallet', '24')
->set('palletAreaSqm', '3.2')
->set('storageRatePerSqmMonth', '11')
->set('effectiveAt', '2026-09-01')
->set('remark', '九月新报价')
->call('save')
->assertHasNoErrors()
->assertSet('message', '仓储报价已保存,新报价不会覆盖历史版本。');
$this->assertDatabaseCount('business_third_party_warehouse_quotes', 2);
$this->assertDatabaseHas('business_third_party_warehouse_quotes', [
'company_id' => company_id(),
'warehouse_name' => '南昌樵舍仓',
'inbound_rate_per_ton' => 22.5,
'outbound_rate_per_order' => 0.9,
'pieces_per_pallet' => 24,
'pallet_area_sqm' => 3.2,
'storage_rate_per_sqm_month' => 11,
'effective_at' => '2026-09-01',
'status' => ThirdPartyWarehouseQuote::STATUS_ACTIVE,
'created_by' => user_id(),
]);
$this->assertSame('20.0000', (string) $existing->fresh()->inbound_rate_per_ton);
}
public function test_warehouse_quote_validation_rejects_zero_divisors(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
Livewire::test(WarehouseQuoteComponent::class)
->set('piecesPerPallet', '0')
->set('palletAreaSqm', '0')
->call('save')
->assertHasErrors(['piecesPerPallet' => 'gt', 'palletAreaSqm' => 'gt']);
}
public function test_warehouse_quote_validation_rejects_a_blank_warehouse_name(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
Livewire::test(WarehouseQuoteComponent::class)
->set('warehouseName', ' ')
->call('save')
->assertHasErrors(['warehouseName' => 'required']);
$this->assertDatabaseCount('business_third_party_warehouse_quotes', 0);
}
public function test_quote_status_action_is_company_scoped(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$quote = ThirdPartyWarehouseQuote::withoutGlobalScopes()->create([
'company_id' => company_id() + 999,
'warehouse_name' => '其他公司仓库',
'inbound_rate_per_ton' => 20,
'outbound_rate_per_order' => 0.85,
'pieces_per_pallet' => 23,
'pallet_area_sqm' => 3,
'storage_rate_per_sqm_month' => 10.5,
'effective_at' => '2026-08-01',
'status' => ThirdPartyWarehouseQuote::STATUS_ACTIVE,
]);
$this->loginAs();
$this->expectException(ModelNotFoundException::class);
Livewire::test(WarehouseQuoteComponent::class)
->call('setStatus', $quote->id, ThirdPartyWarehouseQuote::STATUS_INACTIVE);
}
public function test_daily_sku_storage_detail_can_be_opened_and_switched_by_date(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
$quote = $this->createQuote();
$this->createSettlement($quote, [
['date' => '2026-08-01', 'owner' => '甲', 'sku_code' => 'SKU-A', 'product_name' => '商品A', 'supplier' => '供应商甲', 'category' => '桌类', 'unit' => '件', 'opening' => 100, 'net_movement' => 0, 'closing' => 100, 'storage_fee' => 4.417952],
['date' => '2026-08-01', 'owner' => '甲', 'sku_code' => 'SKU-B', 'product_name' => '商品B', 'supplier' => '供应商乙', 'category' => '柜类', 'unit' => '件', 'opening' => 50, 'net_movement' => 10, 'closing' => 60, 'storage_fee' => 2.650771],
['date' => '2026-08-02', 'owner' => '甲', 'sku_code' => 'SKU-A', 'product_name' => '商品A', 'supplier' => '供应商甲', 'category' => '桌类', 'unit' => '件', 'opening' => 100, 'net_movement' => -10, 'closing' => 90, 'storage_fee' => 3.976157],
]);
Livewire::test(WarehouseQuoteComponent::class)
->call('viewSettlementDetails', '2026-08')
->assertSet('settlementDetailDate', '2026-08-01')
->assertSee('每日商品仓储费明细')
->assertSee('160.00')
->assertSee('SKU-A')
->assertSee('SKU-B')
->set('settlementDetailDate', '2026-08-02')
->assertSee('90.00')
->assertSee('3.976157')
->assertDontSee('SKU-B');
}
public function test_legacy_settlement_explains_that_recalculation_is_required(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
$quote = $this->createQuote();
$this->createSettlement($quote, []);
Livewire::test(WarehouseQuoteComponent::class)
->call('viewSettlementDetails', '2026-08')
->assertSee('原存档没有每日商品明细,请重新核算该月份后查看');
}
public function test_settlement_history_detail_and_export_are_company_scoped(): void
{
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs();
$quote = $this->createQuote();
$this->createSettlement($quote, [], company_id() + 999, '2026-07');
Livewire::test(WarehouseQuoteComponent::class)
->assertDontSee('2026-07')
->call('viewSettlementDetails', '2026-07')
->assertSet('settlementDetailMessage', '未找到 2026-07 的核算存档。')
->call('exportSettlement', '2026-07')
->assertSet('settlementError', '未找到 2026-07 的核算存档,请先核算。');
}
private function createQuote(): ThirdPartyWarehouseQuote
{
return ThirdPartyWarehouseQuote::query()->create([
'company_id' => company_id(),
'warehouse_name' => '南昌樵舍仓',
'inbound_rate_per_ton' => 20,
'outbound_rate_per_order' => 0.85,
'pieces_per_pallet' => 23,
'pallet_area_sqm' => 3,
'storage_rate_per_sqm_month' => 10.5,
'effective_at' => '2026-08-01',
'status' => ThirdPartyWarehouseQuote::STATUS_ACTIVE,
'remark' => '八月合同报价',
'created_by' => $this->user->id,
'updated_by' => $this->user->id,
]);
}
/** @param list<array<string,mixed>> $dailySku */
private function createSettlement(
ThirdPartyWarehouseQuote $quote,
array $dailySku,
?int $companyId = null,
string $period = '2026-08',
): void
{
ThirdPartyWarehouseStorageSettlement::query()->create([
'company_id' => $companyId ?? company_id(),
'warehouse_id' => WarehouseQuoteComponent::WAREHOUSE_ID,
'warehouse_name' => '南昌樵舍仓',
'period' => $period,
'quote_id' => $quote->id,
'inbound_rate_per_ton' => 20,
'outbound_rate_per_order' => 0.85,
'pieces_per_pallet' => 23,
'pallet_area_sqm' => 3,
'storage_rate_per_sqm_month' => 10.5,
'days_in_month' => 31,
'inbound_tons' => 0,
'outbound_qty' => 0,
'inbound_fee' => 0,
'outbound_fee' => 0,
'storage_fee' => array_sum(array_column($dailySku, 'storage_fee')),
'memo_fee' => 0,
'loss_fee' => 0,
'compensation_fee' => 0,
'total_fee' => array_sum(array_column($dailySku, 'storage_fee')),
'detail_json' => ['daily' => [], 'per_sku' => [], 'daily_sku' => $dailySku],
'calculated_by' => user_id(),
]);
}
}