shouldReceive('accessoryReshipBatches')->once()->with('2026-01-01', '2026-02-01', '2025-11-01')->andReturn((function () { yield ['accessories' => [['trade_no' => '001', 'barcode' => 'SKU-1', 'freight' => '2.50']], 'originals' => []]; })()); $data = new AccessoryReshipPageData($repo, new AccessoryReshipMatcher); $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', '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))->page(); $this->assertCount(50, $data['reshipRows']); $this->assertSame(105, $data['reshipRows']->total()); $this->assertSame(105, $data['reshipSummary']['matched']); $this->assertSame(1050, $data['reshipSummary']['amount']); $this->assertSame(105, $data['reshipSummary']['ambiguous']); } }