diff --git a/app/Business/WithdrawalManagementReport.php b/app/Business/WithdrawalManagementReport.php index 0c0a595f..e9d1ae76 100644 --- a/app/Business/WithdrawalManagementReport.php +++ b/app/Business/WithdrawalManagementReport.php @@ -33,7 +33,8 @@ class WithdrawalManagementReport * filters:array{platform:string,withdrawalPath:string,storeEntity:string,keyword:string,balanceStatus:string}, * platforms:list,paths:list,storeEntities:list,rows:Collection, * balances:array, - * reserveStandards:array,summary:array{source:int,matched:int,ambiguous:int,unmatched:int,not_ready:int}, + * reserveStandards:array,withdrawalAmounts:array,compliance:array, + * summary:array{source:int,matched:int,ambiguous:int,unmatched:int,not_ready:int}, * balanceColumnLabel:string,balanceDate:string,sort:array{field:string,direction:string} * } */ @@ -81,9 +82,23 @@ class WithdrawalManagementReport ), ], )->all(); + $withdrawalAmounts = $rows->mapWithKeys( + fn (StoreReceivingAccount $row): array => [ + (int) $row->id => $this->withdrawalAmountFor($row, $balanceDate), + ], + )->all(); + $compliance = $rows->mapWithKeys( + fn (StoreReceivingAccount $row): array => [ + (int) $row->id => $this->complianceFor( + $balances[(int) $row->id] ?? ['status' => 'not_ready', 'balance' => null], + $reserveStandards[(int) $row->id] ?? null, + $withdrawalAmounts[(int) $row->id] ?? null, + ), + ], + )->all(); $rows = $sort['field'] === '' ? $this->sortByBalanceStatus($rows, $balances) - : $this->sortRows($rows, $sort, $balances, $reserveStandards); + : $this->sortRows($rows, $sort, $balances, $reserveStandards, $withdrawalAmounts, $compliance); return [ 'filters' => $filters, @@ -93,6 +108,8 @@ class WithdrawalManagementReport 'rows' => $rows, 'balances' => $balances, 'reserveStandards' => $reserveStandards, + 'withdrawalAmounts' => $withdrawalAmounts, + 'compliance' => $compliance, 'summary' => [ 'source' => $this->shopBalances->countForDate($balanceDate), 'matched' => (int) $balanceCounts->get('matched', 0), @@ -178,13 +195,15 @@ class WithdrawalManagementReport * @param array{field:string,direction:string} $sort * @param array $balances * @param array $reserveStandards + * @param array $withdrawalAmounts + * @param array $compliance * @return Collection */ - private function sortRows(Collection $rows, array $sort, array $balances, array $reserveStandards): Collection + private function sortRows(Collection $rows, array $sort, array $balances, array $reserveStandards, array $withdrawalAmounts, array $compliance): Collection { - return $rows->sort(function (StoreReceivingAccount $left, StoreReceivingAccount $right) use ($sort, $balances, $reserveStandards): int { - $leftValue = $this->sortValue($left, $sort['field'], $balances, $reserveStandards); - $rightValue = $this->sortValue($right, $sort['field'], $balances, $reserveStandards); + return $rows->sort(function (StoreReceivingAccount $left, StoreReceivingAccount $right) use ($sort, $balances, $reserveStandards, $withdrawalAmounts, $compliance): int { + $leftValue = $this->sortValue($left, $sort['field'], $balances, $reserveStandards, $withdrawalAmounts, $compliance); + $rightValue = $this->sortValue($right, $sort['field'], $balances, $reserveStandards, $withdrawalAmounts, $compliance); $comparison = $this->compareSortValues($leftValue, $rightValue, $sort['direction']); return $comparison !== 0 @@ -196,8 +215,10 @@ class WithdrawalManagementReport /** * @param array $balances * @param array $reserveStandards + * @param array $withdrawalAmounts + * @param array $compliance */ - private function sortValue(StoreReceivingAccount $row, string $field, array $balances, array $reserveStandards): mixed + private function sortValue(StoreReceivingAccount $row, string $field, array $balances, array $reserveStandards, array $withdrawalAmounts, array $compliance): mixed { return match ($field) { 'platform' => $row->store_platform, @@ -211,10 +232,34 @@ class WithdrawalManagementReport ? $balances[(int) $row->id]['balance'] : null, 'reserve_standard' => $reserveStandards[(int) $row->id] ?? null, + 'withdrawal_amount' => $withdrawalAmounts[(int) $row->id] ?? null, + 'compliance' => $compliance[(int) $row->id] ?? null, default => null, }; } + private function withdrawalAmountFor(StoreReceivingAccount $row, string $balanceDate): ?float + { + if ($row->withdrawal_balance_date !== $balanceDate || $row->withdrawal_amount === null) { + return null; + } + + return is_numeric($row->withdrawal_amount) ? (float) $row->withdrawal_amount : null; + } + + /** @param array{status:string,balance:?float} $balance */ + private function complianceFor(array $balance, ?int $reserve, ?float $withdrawalAmount): ?string + { + if (($balance['status'] ?? '') !== 'matched' || $balance['balance'] === null || $reserve === null || $withdrawalAmount === null) { + return null; + } + + $remainingCents = (int) round((float) $balance['balance'] * 100) + - (int) round($withdrawalAmount * 100); + + return $remainingCents <= $reserve * 100 ? 'yes' : 'no'; + } + private function compareSortValues(mixed $left, mixed $right, string $direction): int { $leftEmpty = $left === null || $left === ''; diff --git a/app/Business/WithdrawalManagementSpreadsheet.php b/app/Business/WithdrawalManagementSpreadsheet.php index 0b3c12a8..9aa2bc5f 100644 --- a/app/Business/WithdrawalManagementSpreadsheet.php +++ b/app/Business/WithdrawalManagementSpreadsheet.php @@ -34,7 +34,8 @@ class WithdrawalManagementSpreadsheet * @param array{ * rows:\Illuminate\Support\Collection, * balances:array, - * reserveStandards:array,balanceColumnLabel:string,balanceDate:string + * reserveStandards:array,withdrawalAmounts:array,compliance:array, + * balanceColumnLabel:string,balanceDate:string * } $report */ public function export(array $report): StreamedResponse @@ -52,17 +53,17 @@ class WithdrawalManagementSpreadsheet $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('提现管理'); - $this->writeHeader($sheet, self::CONFIG_HEADERS); - $this->sizeColumns($sheet, [14, 30, 20, 32, 16, 24, 22]); + $this->writeHeader($sheet, [...self::CONFIG_HEADERS, '提现金额']); + $this->sizeColumns($sheet, [14, 30, 20, 32, 16, 24, 22, 18]); $instructions = $spreadsheet->createSheet(); $instructions->setTitle('填写说明'); $instructions->fromArray([ ['提现管理导入说明'], ['1. 店铺平台、ERP店铺名称用于定位店铺;有平台店铺ID时优先按平台和ID匹配。'], - ['2. 店铺主体、提现路径、提现账户名称、银行卡号后四位为可更新字段。'], + ['2. 店铺主体、提现路径、提现账户名称、银行卡号后四位和提现金额为可更新字段。'], ['3. 可更新字段留空表示保持原值,填写“' . self::CLEAR_VALUE . '”表示清空原值。'], - ['4. 银行卡号只填写后四位数字。上传后会先展示预览,确认后才写入。'], + ['4. 提现金额须为非负数,最多两位小数,只用于导入当天对应的余额数据日期;上传后先预览再确认。'], ], null, 'A1'); $instructions->getStyle('A1')->getFont()->setBold(true)->setSize(14); $instructions->getColumnDimension('A')->setWidth(88); @@ -96,6 +97,7 @@ class WithdrawalManagementSpreadsheet } [$headerIndex, $headers] = $this->headers($matrix); $indexes = array_flip($headers); + $balanceDate = now()->subDay()->toDateString(); $accounts = StoreReceivingAccount::withoutGlobalScopes() ->where('company_id', $companyId) ->whereNull('deleted_at') @@ -113,6 +115,9 @@ class WithdrawalManagementSpreadsheet foreach (self::CONFIG_HEADERS as $header) { $values[$header] = trim((string) ($row[$indexes[$header]] ?? '')); } + $values['提现金额'] = isset($indexes['提现金额']) + ? trim((string) ($row[$indexes['提现金额']] ?? '')) + : ''; if (count(array_filter($values, static fn (string $value): bool => $value !== '')) === 0) { continue; } @@ -153,7 +158,7 @@ class WithdrawalManagementSpreadsheet $seen[(int) $account->id] = $line; try { - $changes = $this->changes($account, $values); + $changes = $this->changes($account, $values, $balanceDate); } catch (\InvalidArgumentException $exception) { $errors[] = "第 {$line} 行" . $exception->getMessage(); continue; @@ -169,11 +174,13 @@ class WithdrawalManagementSpreadsheet 'receiving_method' => '提现路径', 'receiving_account_name' => '提现账户名称', 'bank_card_last_four' => '银行卡号后四位', + 'withdrawal_amount' => '提现金额', + 'withdrawal_balance_date' => '提现金额', ]; - $changedLabels = array_map( + $changedLabels = array_unique(array_map( static fn (string $field): string => $labels[$field], array_keys($changes), - ); + )); $plan[] = [ 'id' => (int) $account->id, 'updated_at' => (string) $account->getRawOriginal('updated_at'), @@ -230,6 +237,14 @@ class WithdrawalManagementSpreadsheet ]); } + if (isset($item['changes']['withdrawal_balance_date']) + && $item['changes']['withdrawal_balance_date'] !== null + && $item['changes']['withdrawal_balance_date'] !== now()->subDay()->toDateString()) { + throw ValidationException::withMessages([ + 'import' => '余额日期已滚动,请重新上传并预览提现金额。', + ]); + } + foreach ($item['changes'] as $field => $value) { if ($field === 'bank_card_last_four') { $account->bank_card_last_four = $value; @@ -258,6 +273,8 @@ class WithdrawalManagementSpreadsheet foreach ($report['rows'] as $row) { $match = $report['balances'][(int) $row->id] ?? ['status' => 'not_ready', 'balance' => null]; $reserve = $report['reserveStandards'][(int) $row->id] ?? null; + $withdrawalAmount = $report['withdrawalAmounts'][(int) $row->id] ?? null; + $compliance = $report['compliance'][(int) $row->id] ?? null; $textValues = [ 1 => (string) ($row->store_platform ?? ''), 2 => (string) ($row->erp_store_name ?? ''), @@ -281,14 +298,22 @@ class WithdrawalManagementSpreadsheet } else { $sheet->setCellValue([9, $rowNumber], $reserve); } - $sheet->setCellValueExplicit([10, $rowNumber], '待接入', DataType::TYPE_STRING); - $sheet->setCellValueExplicit([11, $rowNumber], '待核验', DataType::TYPE_STRING); + if ($withdrawalAmount === null) { + $sheet->setCellValueExplicit([10, $rowNumber], '待接入', DataType::TYPE_STRING); + } else { + $sheet->setCellValue([10, $rowNumber], $withdrawalAmount); + } + $sheet->setCellValueExplicit([11, $rowNumber], match ($compliance) { + 'yes' => '是', + 'no' => '否', + default => '待核验', + }, DataType::TYPE_STRING); $rowNumber++; } if ($rowNumber > 2) { - $sheet->getStyle('H2:I' . ($rowNumber - 1))->getNumberFormat()->setFormatCode('#,##0.00'); - $sheet->getStyle('H2:I' . ($rowNumber - 1))->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); + $sheet->getStyle('H2:J' . ($rowNumber - 1))->getNumberFormat()->setFormatCode('#,##0.00'); + $sheet->getStyle('H2:J' . ($rowNumber - 1))->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); } $sheet->getStyle('C2:C' . max(2, $rowNumber - 1))->getNumberFormat()->setFormatCode('@'); $sheet->getStyle('G2:G' . max(2, $rowNumber - 1))->getNumberFormat()->setFormatCode('@'); @@ -310,6 +335,9 @@ class WithdrawalManagementSpreadsheet ]); } } + if (count(array_keys($headers, '提现金额', true)) > 1) { + throw ValidationException::withMessages(['import' => '导入表头只能包含一个“提现金额”列。']); + } return [(int) $index, $headers]; } @@ -342,7 +370,7 @@ class WithdrawalManagementSpreadsheet } /** @param array $values @return array */ - private function changes(StoreReceivingAccount $account, array $values): array + private function changes(StoreReceivingAccount $account, array $values, string $balanceDate): array { $fields = [ '店铺主体' => ['field' => 'store_entity_name', 'current' => $account->store_entity_name, 'max' => 191, 'clear' => ''], @@ -373,6 +401,25 @@ class WithdrawalManagementSpreadsheet } } + $amount = $values['提现金额'] ?? ''; + if ($amount !== '' && $amount !== '待接入') { + if ($amount === self::CLEAR_VALUE) { + if ($account->withdrawal_amount !== null || $account->withdrawal_balance_date !== null) { + $changes['withdrawal_amount'] = null; + $changes['withdrawal_balance_date'] = null; + } + } else { + if (preg_match('/^\d{1,10}(?:\.\d{1,2})?$/', $amount) !== 1) { + throw new \InvalidArgumentException('的提现金额须为非负数,最多两位小数'); + } + $normalized = number_format((float) $amount, 2, '.', ''); + if ($account->withdrawal_amount !== $normalized || $account->withdrawal_balance_date !== $balanceDate) { + $changes['withdrawal_amount'] = $normalized; + $changes['withdrawal_balance_date'] = $balanceDate; + } + } + } + return $changes; } diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 510abf55..fa484b05 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -891,6 +891,8 @@ class Pages extends Controller 'withdrawalStoreEntities' => $report['storeEntities'], 'withdrawalBalances' => $report['balances'], 'withdrawalReserveStandards' => $report['reserveStandards'], + 'withdrawalAmounts' => $report['withdrawalAmounts'], + 'withdrawalCompliance' => $report['compliance'], 'withdrawalBalanceSummary' => $report['summary'], 'withdrawalBalanceColumnLabel' => $report['balanceColumnLabel'], 'withdrawalBalanceDate' => $report['balanceDate'], diff --git a/app/Models/Business/StoreReceivingAccount.php b/app/Models/Business/StoreReceivingAccount.php index 5b9a98cd..2dba7cf0 100644 --- a/app/Models/Business/StoreReceivingAccount.php +++ b/app/Models/Business/StoreReceivingAccount.php @@ -23,6 +23,8 @@ class StoreReceivingAccount extends Model 'bank_card_last_four' => 'b', 'store_id' => 'i', 'source_platform' => 'r', + 'withdrawal_amount' => 'm', + 'withdrawal_balance_date' => 'd', ]; protected $table = 'business_store_receiving_accounts'; @@ -35,6 +37,7 @@ class StoreReceivingAccount extends Model 'payment_password', 'payment_verification_method', 'financial_account', 'financial_password', 'payment_verification_method_secondary', 'withdrawal_path', 'withdrawal_account_name', 'bank_card_last_four', 'store_id', 'source_platform', + 'withdrawal_amount', 'withdrawal_balance_date', ]; protected $casts = [ @@ -213,6 +216,26 @@ class StoreReceivingAccount extends Model $this->setMeta('source_platform', $this->clean($value)); } + public function getWithdrawalAmountAttribute(): ?string + { + return $this->meta('withdrawal_amount'); + } + + public function setWithdrawalAmountAttribute($value): void + { + $this->setMeta('withdrawal_amount', $this->clean($value)); + } + + public function getWithdrawalBalanceDateAttribute(): ?string + { + return $this->meta('withdrawal_balance_date'); + } + + public function setWithdrawalBalanceDateAttribute($value): void + { + $this->setMeta('withdrawal_balance_date', $this->clean($value)); + } + private function clean($value): ?string { $value = trim((string) $value); diff --git a/resources/views/business/pages/fund-management/withdrawal-management.blade.php b/resources/views/business/pages/fund-management/withdrawal-management.blade.php index 8fb22873..f0b3d0f6 100644 --- a/resources/views/business/pages/fund-management/withdrawal-management.blade.php +++ b/resources/views/business/pages/fund-management/withdrawal-management.blade.php @@ -168,6 +168,8 @@ ? '聚水潭店铺:' . $balanceMatch['source_store_name'] . ';余额日期:' . $withdrawalBalanceDate : '余额日期:' . $withdrawalBalanceDate; $reserveStandard = $withdrawalReserveStandards[(int) $row->id] ?? null; + $withdrawalAmount = $withdrawalAmounts[(int) $row->id] ?? null; + $compliance = $withdrawalCompliance[(int) $row->id] ?? null; @endphp {{ $row->store_platform ?: '未配置' }} @@ -179,8 +181,16 @@ {{ $bankCard }} {{ $balanceText }} {{ $reserveStandard === null ? '待配置' : number_format($reserveStandard, 2) }} - 待接入 - 待核验 + {{ $withdrawalAmount === null ? '待接入' : number_format($withdrawalAmount, 2) }} + + @if ($compliance === 'yes') + 是 + @elseif ($compliance === 'no') + 否 + @else + 待核验 + @endif + @empty diff --git a/tests/Feature/Business/WithdrawalManagementImportExportTest.php b/tests/Feature/Business/WithdrawalManagementImportExportTest.php index 2773ee4a..be6f98e6 100644 --- a/tests/Feature/Business/WithdrawalManagementImportExportTest.php +++ b/tests/Feature/Business/WithdrawalManagementImportExportTest.php @@ -4,9 +4,13 @@ namespace Tests\Feature\Business; use App\Models\Auth\Permission; use App\Models\Business\StoreReceivingAccount; +use App\Business\WithdrawalManagementReport; use Illuminate\Http\UploadedFile; use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; +use Mockery; +use Modules\EcommerceFinance\Repositories\JushuitanShopBalanceRepository; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -25,6 +29,8 @@ class WithdrawalManagementImportExportTest extends FeatureTestCase '银行卡号(后四位)', ]; + private const IMPORT_HEADERS = [...self::HEADERS, '提现金额']; + /** @var list */ private array $temporaryFiles = []; @@ -163,7 +169,7 @@ class WithdrawalManagementImportExportTest extends FeatureTestCase $spreadsheet = IOFactory::load($path); try { - $this->assertSame(self::HEADERS, $spreadsheet->getSheet(0)->rangeToArray('A1:G1')[0]); + $this->assertSame(self::IMPORT_HEADERS, $spreadsheet->getSheet(0)->rangeToArray('A1:H1')[0]); $this->assertSame('填写说明', $spreadsheet->getSheet(1)->getTitle()); $this->assertStringContainsString('[清空]', (string) $spreadsheet->getSheet(1)->getCell('A4')->getValue()); } finally { @@ -319,6 +325,132 @@ class WithdrawalManagementImportExportTest extends FeatureTestCase $this->assertSame('他人已修改主体', $store->fresh()->store_entity_name); } + public function test_compliance_uses_balance_minus_current_date_withdrawal_and_matches_export(): void + { + Carbon::setTestNow('2026-09-24 09:00:00'); + + try { + $stores = []; + foreach ([ + ['达标测试店', '5000.00', '2026-09-23'], + ['未达标测试店', '4999.99', '2026-09-23'], + ['过期金额测试店', '5000.00', '2026-09-22'], + ['缺少金额测试店', null, null], + ['缺少余额测试店', '5000.00', '2026-09-23'], + ] as [$name, $amount, $date]) { + $stores[$name] = StoreReceivingAccount::query()->create([ + 'company_id' => $this->company->id, + 'store_platform' => '京东', + 'erp_store_name' => $name, + 'store_entity_name' => '测试主体', + 'withdrawal_amount' => $amount, + 'withdrawal_balance_date' => $date, + ]); + } + $stores['缺少标准测试店'] = StoreReceivingAccount::query()->create([ + 'company_id' => $this->company->id, + 'store_platform' => '唯品会', + 'erp_store_name' => '缺少标准测试店', + 'store_entity_name' => '测试主体', + 'withdrawal_amount' => '5000.00', + 'withdrawal_balance_date' => '2026-09-23', + ]); + + $balances = []; + foreach ($stores as $store) { + $balances[(int) $store->id] = [ + 'status' => $store->erp_store_name === '缺少余额测试店' ? 'unmatched' : 'matched', + 'balance' => $store->erp_store_name === '缺少余额测试店' ? null : 10000.00, + 'source_store_name' => $store->erp_store_name, + 'source_platform' => '京东', + ]; + } + $mirror = Mockery::mock(JushuitanShopBalanceRepository::class); + $mirror->shouldReceive('matchesForStores')->andReturn($balances); + $mirror->shouldReceive('countForDate')->andReturn(6); + $this->app->instance(JushuitanShopBalanceRepository::class, $mirror); + + $report = $this->app->make(WithdrawalManagementReport::class)->results(request()); + $this->assertSame('yes', $report['compliance'][(int) $stores['达标测试店']->id]); + $this->assertSame('no', $report['compliance'][(int) $stores['未达标测试店']->id]); + $this->assertNull($report['compliance'][(int) $stores['过期金额测试店']->id]); + $this->assertNull($report['compliance'][(int) $stores['缺少金额测试店']->id]); + $this->assertNull($report['compliance'][(int) $stores['缺少余额测试店']->id]); + $this->assertNull($report['compliance'][(int) $stores['缺少标准测试店']->id]); + + $page = $this->loginAs()->get(route('business.pages.show', [ + 'section' => 'fund-management', + 'page' => 'withdrawal-management', + 'platform' => '京东', + ])); + $page->assertOk() + ->assertSeeText('待核验'); + $this->assertMatchesRegularExpression('/data-withdrawal-column="compliance">\s*是<\/span>/', $page->getContent()); + $this->assertMatchesRegularExpression('/data-withdrawal-column="compliance">\s*否<\/span>/', $page->getContent()); + + $response = $this->get(route('business.withdrawal-management.export', ['platform' => '京东'])); + $path = $this->temporaryPath('withdrawal-compliance-export-'); + file_put_contents($path, $response->streamedContent()); + $spreadsheet = IOFactory::load($path); + try { + $sheet = $spreadsheet->getActiveSheet(); + $values = []; + for ($row = 2; $row <= $sheet->getHighestDataRow(); $row++) { + $values[(string) $sheet->getCell("B{$row}")->getValue()] = [ + $sheet->getCell("J{$row}")->getValue(), + $sheet->getCell("K{$row}")->getValue(), + ]; + } + $this->assertSame([5000.0, '是'], $values['达标测试店']); + $this->assertSame([4999.99, '否'], $values['未达标测试店']); + $this->assertSame(['待接入', '待核验'], $values['过期金额测试店']); + $this->assertSame(['待接入', '待核验'], $values['缺少金额测试店']); + $this->assertSame([5000.0, '待核验'], $values['缺少余额测试店']); + } finally { + $spreadsheet->disconnectWorksheets(); + } + } finally { + Carbon::setTestNow(); + } + } + + public function test_withdrawal_amount_import_is_validated_and_bound_to_current_balance_date(): void + { + Carbon::setTestNow('2026-09-24 09:00:00'); + + try { + $store = StoreReceivingAccount::query()->create([ + 'company_id' => $this->company->id, + 'store_platform' => '京东', + 'erp_store_name' => '金额导入测试店', + 'store_entity_name' => '测试主体', + ]); + $this->loginAs(); + $this->withExceptionHandling() + ->post(route('business.withdrawal-management.import.preview'), [ + 'import' => $this->workbook([['京东', '金额导入测试店', '', '', '', '', '', '-1']]), + ]) + ->assertSessionHasErrors('import'); + $this->assertNull($store->fresh()->withdrawal_amount); + + $previewResponse = $this->post(route('business.withdrawal-management.import.preview'), [ + 'import' => $this->workbook([['京东', '金额导入测试店', '', '', '', '', '', '5000.00']]), + ]); + $previewResponse->assertSessionHas('withdrawalImportPreview', function (array $preview): bool { + return $preview['preview'][0]['changes'] === '提现金额'; + }); + $preview = $previewResponse->getSession()->get('withdrawalImportPreview'); + $this->post(route('business.withdrawal-management.import.commit'), [ + 'preview_token' => $preview['token'], + ])->assertSessionHasNoErrors(); + + $this->assertSame('5000.00', $store->fresh()->withdrawal_amount); + $this->assertSame('2026-09-23', $store->fresh()->withdrawal_balance_date); + } finally { + Carbon::setTestNow(); + } + } + /** @param list> $rows */ private function workbook(array $rows): UploadedFile { @@ -326,7 +458,7 @@ class WithdrawalManagementImportExportTest extends FeatureTestCase $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('提现管理'); - $sheet->fromArray(self::HEADERS, null, 'A1'); + $sheet->fromArray(self::IMPORT_HEADERS, null, 'A1'); if ($rows !== []) { $sheet->fromArray($rows, null, 'A2'); }