feat: 流程明细按打款日期筛选 #644

Merged
yueyang merged 1 commits from feature/yueyang-process-details-paid-date into main 2026-10-26 20:10:47 +08:00
8 changed files with 35 additions and 45 deletions

View File

@ -39,7 +39,6 @@ class ProcessDetails extends Controller
),
'filters' => $filters,
'summary' => $result['summary'],
'months' => $options['months'],
'documentTypes' => $options['document_types'],
'statuses' => $options['statuses'],
'mirrorStatus' => $result['status'],
@ -64,7 +63,6 @@ class ProcessDetails extends Controller
'amount_total' => 0.0,
'bank_amount_total' => 0.0,
],
'months' => [],
'documentTypes' => [],
'statuses' => [],
'mirrorStatus' => 'unavailable',
@ -124,11 +122,13 @@ class ProcessDetails extends Controller
/** @return array<string,string> */
private function filters(Request $request): array
{
$month = trim((string) $request->query('month', ''));
$paidDate = trim((string) $request->query('paid_date', ''));
$status = trim((string) $request->query('status', ''));
$paidDateValid = preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $paidDate, $dateParts) === 1
&& checkdate((int) $dateParts[2], (int) $dateParts[3], (int) $dateParts[1]);
return [
'month' => preg_match('/^\d{4}-\d{2}$/', $month) === 1 ? $month : '',
'paid_date' => $paidDateValid ? $paidDate : '',
'document_type' => mb_substr(trim((string) $request->query('document_type', '')), 0, 100),
'status' => mb_substr($status, 0, 20),
'business_id' => mb_substr(trim((string) $request->query('business_id', '')), 0, 32),

View File

@ -115,31 +115,17 @@ class DingProcessDetailMirrorRepository
];
}
/** @return array{months:list<string>,document_types:list<string>,statuses:list<string>} */
/** @return array{document_types:list<string>,statuses:list<string>} */
public function filterOptions(): array
{
if (! Schema::connection($this->connection->getName())->hasTable('ding_process_detail_mirror')) {
return ['months' => [], 'document_types' => [], 'statuses' => []];
return ['document_types' => [], 'statuses' => []];
}
$base = $this->connection->table('ding_process_detail_mirror')
->where('source_scope', $this->scope());
return [
'months' => (clone $base)
->whereNotNull('business_month')
->where('business_month', '!=', '')
->distinct()
->orderByDesc('business_month')
->pluck('business_month')
->map(static function (mixed $value): string {
$month = (string) $value;
return preg_match('/^\d{6}$/', $month) === 1
? substr($month, 0, 4) . '-' . substr($month, 4, 2)
: $month;
})
->all(),
'document_types' => (clone $base)
->whereNotNull('document_type')
->where('document_type', '!=', '')
@ -191,9 +177,9 @@ class DingProcessDetailMirrorRepository
$query = $this->connection->table('ding_process_detail_mirror')
->where('source_scope', $this->scope());
$month = trim((string) ($filters['month'] ?? ''));
if (preg_match('/^\d{4}-\d{2}$/', $month) === 1) {
$query->where('business_month', str_replace('-', '', $month));
$paidDate = trim((string) ($filters['paid_date'] ?? ''));
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $paidDate) === 1) {
$query->where('paid_at', 'like', $paidDate . '%');
}
foreach ([

View File

@ -34,7 +34,6 @@ class ProcessDetailsPageData
),
'filters' => $filters,
'summary' => $result['summary'],
'months' => $options['months'],
'documentTypes' => $options['document_types'],
'statuses' => $options['statuses'],
'mirrorStatus' => $result['status'],
@ -57,7 +56,6 @@ class ProcessDetailsPageData
'amount_total' => 0.0,
'bank_amount_total' => 0.0,
],
'months' => [],
'documentTypes' => [],
'statuses' => [],
'mirrorStatus' => 'unavailable',
@ -71,11 +69,13 @@ class ProcessDetailsPageData
/** @return array<string,string> */
private function filters(Request $request): array
{
$month = trim((string) $request->query('month', ''));
$paidDate = trim((string) $request->query('paid_date', ''));
$status = trim((string) $request->query('status', ''));
$paidDateValid = preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $paidDate, $dateParts) === 1
&& checkdate((int) $dateParts[2], (int) $dateParts[3], (int) $dateParts[1]);
return [
'month' => preg_match('/^\d{4}-\d{2}$/', $month) === 1 ? $month : '',
'paid_date' => $paidDateValid ? $paidDate : '',
'document_type' => mb_substr(trim((string) $request->query('document_type', '')), 0, 100),
'status' => mb_substr($status, 0, 20),
'business_id' => mb_substr(trim((string) $request->query('business_id', '')), 0, 32),

View File

@ -510,8 +510,8 @@
<form method="GET" action="{{ $pageUrl }}" class="process-details-toolbar" aria-label="流程明细筛选">
<div class="process-details-field">
<label for="process-details-month">月份</label>
<input id="process-details-month" type="month" name="month" value="{{ $filters['month'] ?? '' }}">
<label for="process-details-paid-date">打款日期</label>
<input id="process-details-paid-date" type="date" name="paid_date" value="{{ $filters['paid_date'] ?? '' }}">
</div>
<div class="process-details-field">
<label for="process-details-type">单据类型</label>

View File

@ -5,7 +5,6 @@
$processRows = $pageData['processRows'];
$filters = $pageData['filters'];
$summary = $pageData['summary'];
$months = $pageData['months'];
$documentTypes = $pageData['documentTypes'];
$statuses = $pageData['statuses'];
$mirrorStatus = $pageData['mirrorStatus'];
@ -15,7 +14,6 @@
}
$filters = $filters ?? [];
$summary = $summary ?? [];
$months = $months ?? [];
$documentTypes = $documentTypes ?? [];
$statuses = $statuses ?? [];
$error = $error ?? null;

View File

@ -46,7 +46,6 @@ class ProcessDetailsPageTest extends FeatureTestCase
'scope' => 'personal_permission',
]);
$repository->shouldReceive('filterOptions')->once()->andReturn([
'months' => ['2026-01'],
'document_types' => ['公摊日常报销'],
'statuses' => ['已完成'],
]);
@ -67,6 +66,8 @@ class ProcessDetailsPageTest extends FeatureTestCase
->assertSee('审批编号')
->assertSee('发起人')
->assertSee('单据类型')
->assertSee('打款日期')
->assertSee('name="paid_date"', false)
->assertSee('银行付款金额')
->assertSee('202601011200000000001')
->assertSee('张三')

View File

@ -46,18 +46,22 @@ class DingProcessDetailMirrorRepositoryTest extends TestCase
$this->assertSame('personal_permission', $result['scope']);
$options = $this->repository->filterOptions();
$this->assertSame(['2026-02', '2026-01'], $options['months']);
$this->assertArrayNotHasKey('months', $options);
$this->assertContains('公摊日常报销', $options['document_types']);
$this->assertContains('应付申请流程', $options['document_types']);
$this->assertContains('已完成', $options['statuses']);
$this->assertContains('审批中', $options['statuses']);
}
public function test_paginate_applies_month_status_and_keyword_filters(): void
public function test_paginate_applies_paid_date_status_and_keyword_filters(): void
{
$this->assertSame(
2,
$this->repository->paginate(['month' => '2026-01'], 1, 50)['total'],
1,
$this->repository->paginate(['paid_date' => '2026-01-02'], 1, 50)['total'],
);
$this->assertSame(
1,
$this->repository->paginate(['paid_date' => '2026-02-03'], 1, 50)['total'],
);
$this->assertSame(
2,
@ -110,10 +114,10 @@ class DingProcessDetailMirrorRepositoryTest extends TestCase
{
$now = now();
$rows = [
$this->row('202601011200000000001', 1, '202601', '张三', '已完成', '公摊日常报销', '办公用品采购', 100.00),
$this->row('202601011200000000001', 2, '202601', '张三', '已完成', '公摊日常报销', '交通费', 50.50),
$this->row('202602031200000000002', 1, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 200.00),
$this->row('202602031200000000002', 2, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 300.00),
$this->row('202601011200000000001', 1, '202601', '张三', '已完成', '公摊日常报销', '办公用品采购', 100.00, '2026-01-02 00:00'),
$this->row('202601011200000000001', 2, '202601', '张三', '已完成', '公摊日常报销', '交通费', 50.50, '2026-01-15 00:00'),
$this->row('202602031200000000002', 1, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 200.00, '2026-02-03 00:00'),
$this->row('202602031200000000002', 2, '202602', '李四', '审批中', '应付申请流程', '供应商货款', 300.00, '2026-02-20 00:00'),
];
DB::connection('business_mirror')
@ -151,6 +155,7 @@ class DingProcessDetailMirrorRepositoryTest extends TestCase
string $documentType,
string $purpose,
float $amount,
string $paidAt,
): array {
$now = now();
@ -169,7 +174,7 @@ class DingProcessDetailMirrorRepositoryTest extends TestCase
'bank_account_name' => '华夏银行-测试',
'bank_amount' => $amount,
'payment_method' => '银行卡',
'paid_at' => '2026-01-02 00:00',
'paid_at' => $paidAt,
'source_scope' => 'personal_permission',
'synced_at' => $now,
'created_at' => $now,

View File

@ -44,7 +44,7 @@ class ProcessDetailsPageDataTest extends TestCase
$repository = $this->createMock(DingProcessDetailMirrorRepository::class);
$repository->expects($this->once())
->method('paginate')
->with($this->callback(static fn (array $filters): bool => $filters['month'] === '2026-10'), 2, 50)
->with($this->callback(static fn (array $filters): bool => $filters['paid_date'] === '2026-10-24'), 2, 50)
->willReturn([
'data' => [$row],
'total' => 11331,
@ -61,7 +61,6 @@ class ProcessDetailsPageDataTest extends TestCase
$repository->expects($this->once())
->method('filterOptions')
->willReturn([
'months' => ['2026-10'],
'document_types' => ['种菜核销/种菜报销'],
'statuses' => ['审批中'],
]);
@ -69,7 +68,7 @@ class ProcessDetailsPageDataTest extends TestCase
$data = (new ProcessDetailsPageData($repository))->page(Request::create(
'/1/workspace/financial-operations/process-details',
'GET',
['month' => '2026-10', 'page' => 2],
['paid_date' => '2026-10-24', 'page' => 2],
));
$this->assertInstanceOf(LengthAwarePaginator::class, $data['processRows']);
@ -79,7 +78,8 @@ class ProcessDetailsPageDataTest extends TestCase
$this->assertSame($row, $data['processRows']->items()[0]);
$this->assertSame('succeeded', $data['mirrorStatus']);
$this->assertSame(11331, $data['summary']['rows']);
$this->assertSame(['2026-10'], $data['months']);
$this->assertSame('2026-10-24', $data['filters']['paid_date']);
$this->assertArrayNotHasKey('months', $data);
$this->assertNull($data['error']);
}
}