CaiWuXiTong/tests/Unit/AccessoryReshipPageDataTest.php

68 lines
4.1 KiB
PHP

<?php
namespace Tests\Unit;
use Illuminate\Container\Container;
use Illuminate\Http\Request;
use Modules\EcommerceFinance\Repositories\ShippingOrderRepository;
use Modules\EcommerceFinance\Services\AccessoryReshipMatcher;
use Modules\EcommerceFinance\View\AccessoryReshipPageData;
use Modules\EcommerceFinance\Services\AccessoryReshipCourierStore;
use Modules\EcommerceFinance\Services\AccessoryReshipRateCalculator;
use Modules\EcommerceFinance\Services\AccessoryReshipSelectionStore;
use PHPUnit\Framework\TestCase;
use Mockery;
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/Repositories/ShippingOrderRepository.php';
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/Services/AccessoryReshipMatcher.php';
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/View/AccessoryReshipPageData.php';
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/Services/AccessoryReshipCourierStore.php';
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/Services/AccessoryReshipRateCalculator.php';
require_once dirname(__DIR__, 2) . '/modules/EcommerceFinance/Services/AccessoryReshipSelectionStore.php';
class AccessoryReshipPageDataTest extends TestCase
{
private function selections(): AccessoryReshipSelectionStore
{
$store = Mockery::mock(AccessoryReshipSelectionStore::class);
$store->shouldReceive('forMonth')->andReturn([]);
return $store;
}
private function configs(): AccessoryReshipCourierStore
{
$store = Mockery::mock(AccessoryReshipCourierStore::class);
$store->shouldReceive('activeRates')->andReturn(['快递' => ['courier_code' => 'TEST', 'rate_basis_points' => 5000]]);
return $store;
}
protected function tearDown(): void { Mockery::close(); parent::tearDown(); }
public function test_january_uses_current_month_and_previous_two_months(): void
{
$repo = Mockery::mock(ShippingOrderRepository::class);
$repo->shouldReceive('accessoryReshipBatches')->once()->with('2026-01-01', '2026-02-01', '2025-11-01')->andReturn((function () { yield ['accessories' => [['trade_no' => '001', 'express_no' => 'BF001', 'express_name1' => '补发快递', 'ship_time' => '2026-09-01', 'barcode' => 'SKU-1', 'freight' => '2.50']], 'originals' => []]; })());
$data = new AccessoryReshipPageData($repo, new AccessoryReshipMatcher, $this->configs(), new AccessoryReshipRateCalculator, $this->selections());
$rows = iterator_to_array($data->rows(['month' => '2026-01']));
$this->assertSame('unmatched', $rows[0]['status']);
$this->assertSame(0, $rows[0]['deduction_cents']);
}
public function test_summary_does_not_duplicate_candidate_freight_and_paginates(): void
{
$request = Request::create('/workspace/courier-payables/accessory-reship-deductions?month=2026-09&match_status=all&page=2');
Container::getInstance()->instance('request', $request);
$accessories = [];
for ($i = 0; $i < 105; $i++) $accessories[] = ['trade_no' => '001', 'express_no' => 'BF001', 'express_name1' => '补发快递', 'ship_time' => '2026-09-01', 'barcode' => 'SKU-1', 'freight' => '0.10'];
$original = ['trade_no' => '001', 'barcode' => 'SKU', 'express_no' => 'FIRST', 'express_name1' => '快递', 'ship_time' => '2026-08-01', 'warehouse_name' => '成品仓'];
$repo = Mockery::mock(ShippingOrderRepository::class);
$repo->shouldReceive('accessoryReshipBatches')->andReturn((function () use ($accessories, $original) { yield ['accessories' => $accessories, 'originals' => [$original, array_replace($original, ['express_no' => 'SECOND'])]]; })());
$data = (new AccessoryReshipPageData($repo, new AccessoryReshipMatcher, $this->configs(), new AccessoryReshipRateCalculator, $this->selections()))->page();
$this->assertCount(50, $data['reshipRows']);
$this->assertSame(105, $data['reshipRows']->total());
$this->assertSame(105, $data['reshipSummary']['matched']);
$this->assertSame(525, $data['reshipSummary']['amount']);
$this->assertSame(105, $data['reshipSummary']['ready']);
$this->assertSame(0, $data['reshipSummary']['ambiguous']);
}
}