修复支付宝账单翻页重复全表计数 (#131)
This commit is contained in:
parent
f2508eeaeb
commit
230962f6a3
@ -40,7 +40,14 @@ class StoreReceivingAlipayBillMirrorRepository
|
||||
|
||||
$query = $this->billQuery();
|
||||
$this->applyFilters($query, $filters);
|
||||
$total = (clone $query)->count();
|
||||
$state = $this->mirror->state($dataset) ?? [];
|
||||
// The synchronizer persists an exact COUNT in the same transaction that
|
||||
// marks a run successful. Never substitute a database row estimate.
|
||||
$hasFilters = collect($filters)->contains(static fn (mixed $value): bool => $value !== null && trim((string) $value) !== '');
|
||||
$recordedCount = $state['mirror_row_count'] ?? null;
|
||||
$useRecordedCount = ! $hasFilters && ($state['status'] ?? null) === 'succeeded'
|
||||
&& $recordedCount !== null && ctype_digit((string) $recordedCount);
|
||||
$total = $useRecordedCount ? (int) $recordedCount : (clone $query)->count();
|
||||
$summary = $this->summary($query, $filters);
|
||||
|
||||
$billRows = $query
|
||||
@ -54,7 +61,6 @@ class StoreReceivingAlipayBillMirrorRepository
|
||||
$rows = collect($billRows)
|
||||
->map(fn (object $row): array => $this->mapRow($row, $shopNames[(string) $row->shop_id] ?? null))
|
||||
->all();
|
||||
$state = $this->mirror->state($dataset) ?? [];
|
||||
$income = $summary['income'];
|
||||
$expense = $summary['expense'];
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ class StoreReceivingAlipayBillMirrorRepositoryTest extends TestCase
|
||||
$table->dateTime('initial_completed_at')->nullable();
|
||||
$table->string('status')->nullable();
|
||||
$table->dateTime('last_succeeded_at')->nullable();
|
||||
$table->unsignedBigInteger('mirror_row_count')->nullable();
|
||||
});
|
||||
$schema->create('ops_jst_original_bill_info', function (Blueprint $table): void {
|
||||
$table->integer('Id');
|
||||
@ -160,6 +161,38 @@ class StoreReceivingAlipayBillMirrorRepositoryTest extends TestCase
|
||||
$this->assertSame(['income' => 100.25, 'expense' => 20.10, 'balance' => 80.15, 'count' => 1], $result['summary']);
|
||||
}
|
||||
|
||||
public function test_unfiltered_pages_reuse_exact_completed_count_and_observe_the_next_sync(): void
|
||||
{
|
||||
$this->markReady();
|
||||
$db = DB::connection('business_mirror');
|
||||
$db->table('ops_jst_original_bill_info')->insert([
|
||||
$this->row(1, 7, '2026-08-01 09:00:00', '1', 10),
|
||||
$this->row(2, 7, '2026-08-02 09:00:00', '-1', 5),
|
||||
]);
|
||||
$state = $db->table('business_mirror_table_states')->where('dataset_key', StoreReceivingAlipayBillMirrorRepository::DATASET);
|
||||
$state->update(['mirror_row_count' => 2]);
|
||||
$db->enableQueryLog();
|
||||
$first = $this->repository->paginate([], 'occurred_at', 'desc', 1, 1);
|
||||
$second = $this->repository->paginate(['store_name' => '', 'start' => null], 'occurred_at', 'desc', 2, 1);
|
||||
$this->assertSame(2, $first['total']);
|
||||
$this->assertSame(2, $second['total']);
|
||||
$this->assertNotSame($first['data'][0]['id'], $second['data'][0]['id']);
|
||||
$this->assertCount(0, array_filter($db->getQueryLog(), fn ($q) => str_contains(strtolower($q['query']), 'count(*)')));
|
||||
$db->disableQueryLog();
|
||||
|
||||
$db->table('ops_jst_original_bill_info')->insert($this->row(3, 7, '2026-08-03 09:00:00', '1', 4));
|
||||
$state->update(['mirror_row_count' => 3, 'last_succeeded_at' => '2026-09-08 09:00:00']);
|
||||
$this->assertSame(3, $this->repository->paginate([], 'occurred_at', 'desc', 1, 1)['total']);
|
||||
$this->assertSame(1, $this->repository->paginate(['business_type' => '支出'], 'occurred_at', 'desc', 1, 1)['total']);
|
||||
|
||||
$state->update(['status' => 'running', 'mirror_row_count' => 2]);
|
||||
$this->assertSame(3, $this->repository->paginate([], 'occurred_at', 'desc', 1, 1)['total']);
|
||||
$state->update(['status' => 'failed']);
|
||||
$this->assertSame(3, $this->repository->paginate([], 'occurred_at', 'desc', 1, 1)['total']);
|
||||
$state->update(['status' => 'succeeded', 'mirror_row_count' => null]);
|
||||
$this->assertSame(3, $this->repository->paginate([], 'occurred_at', 'desc', 1, 1)['total']);
|
||||
}
|
||||
|
||||
private function markReady(): void
|
||||
{
|
||||
foreach ([StoreReceivingAlipayBillMirrorRepository::DATASET, StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET] as $dataset) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user